/**
 *  ---------
 * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
 * |#       #|
 * |#       #|  Copyright (c) 1999-2020 CardContact Software & System Consulting
 * |'##> <##'|  Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de)
 *  ---------
 *
 *  This file is part of OpenSCDP.
 *
 *  OpenSCDP is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  OpenSCDP is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with OpenSCDP; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * @fileoverview Personalization Client forthe PKI-as-a-Service Portal
 */

var SmartCardHSM = require('scsh/sc-hsm/SmartCardHSM').SmartCardHSM;
var CVC = require("scsh/eac/CVC").CVC;
var DICATask = require("scsh/perso/DICATask").DICATask;


function PortalPersonalizer(job) {
	this.job = job;
}

exports.PortalPersonalizer = PortalPersonalizer;

PortalPersonalizer.type = "personalizer";




PortalPersonalizer.prototype.configure = function() {
	this.parseSubjectURL();
	this.login();
	if (typeof(this.job.dicaId) != "undefined") {
		this.dicaId = this.job.dicaId;
	} else {
		this.getDICA();
	}
	if (Dialog.prompt("Connect DICA Token to Portal ?")) {
		this.attachDICA();
	}
}



PortalPersonalizer.prototype.parseSubjectURL = function(url) {

	var url = "https://www.pki-as-a-service.net/se/paas/subject/<id>";
	var subjectPath = "/se/paas/subject/";
	var prompt = true;

	if (typeof(this.job.url) != "undefined") {
		url = this.job.url;
	}

	while (true) {
		var pathIdx = url.indexOf(subjectPath);
		if (pathIdx < 0) {
			assert(Dialog.prompt("URL must contain " + subjectPath));
		} else {
			var id = parseInt(url.substring(pathIdx + subjectPath.length));
			if (isNaN(id)) {
				assert(Dialog.prompt("URL must contain a subject id after " + subjectPath));
			} else {
				break;
			}
		}

		url = Dialog.prompt("Enter the URL of the Device Issuer", url);
		assert(url, "User abort");
	}

	this.host = url.substring(0, pathIdx);
	this.subjectId = id;
}



PortalPersonalizer.prototype.attachDICA = function() {
	var readerList = Card.getReaderList();
	var lastreader = _scsh3.DICAToken;
	if (!lastreader) {
		lastreader = _scsh3.reader;
	}
	while (true) {
		var reader = Dialog.prompt("Please select reader with DICA token", lastreader, readerList);
		assert(reader, "User abort");
		_scsh3.setProperty("DICAToken", reader);

		try	{
			var card = new Card(reader);
			var sc = new SmartCardHSM(card);
			sc.verifyUserPIN();
			break;
		}
		catch(e) {
			print(e);
		}
	}

	var idx = this.host.lastIndexOf(":");
	if (idx >= 0) {
		var url = this.host.substr(0, idx) + ":8081/rt/hsm";
	} else {
		var url = this.host + "/sems-rt/";
	}

	url = Dialog.prompt("Connect to", url);
	assert(url, "User abort");

	this.dicatask = new DICATask(card, url);
	this.dicatask.start();
}



PortalPersonalizer.prototype.login = function() {
	default xml namespace = "http://www.w3.org/1999/xhtml";

	var login2 = false;
	// Get new session
	var baseURL = this.host + "/se";
	var c = new URLConnection(baseURL);
	c.addHeaderField("Accept", "application/json");
	var result = c.get();

	var cookie = c.getHeaderField("Set-Cookie");
	this.session = cookie[0].substr(0, cookie[0].indexOf(";"));

	if (c.contentType == "application/json") {
		login2 = true;
		print(result);
		result = JSON.parse(result);

		var conInfo = {
			url: result.rt.url,
			pinrequired: result.rt.pinRequired,
			sessionId: result.rt.sessionId
		};
	} else {
		// Get connection string

		c.addHeaderField("Cookie", this.session);
		var result = c.get();

		var html = result.match(/<html xmlns="http:\/\/www.w3.org\/1999\/xhtml" lang="en" xml:lang="en">[\s\S]*<\/html>/);
		var page = new XML(html);

		var content = page..div.(@id == "content");
		var img = content..img;
		var remoteStr = img.@src.toXMLString();

		var queryStr = remoteStr.substr(remoteStr.indexOf("?") + 1);

		var params = queryStr.split("&amp;");
		var conInfo = {};
		for (var i = 0; i < params.length; i++) {
			var param = params[i];
			var res = param.split("=");
			conInfo[res[0]] = res[1];
		}
	}


	// Authenticate with login token

	var readerList = Card.getReaderList();
	var lastreader = _scsh3.portalReader;
	if (!lastreader) {
		lastreader = _scsh3.reader;
	}
	var reader = Dialog.prompt("Please select reader with token to log in", lastreader, readerList);
	assert(reader, "User abort");
	_scsh3.setProperty("portalReader", reader);

	var card = new Card(reader);

	if (conInfo.pinrequired == 1) {
		GPSystem.trace("Authenticate User");
		var sc = new SmartCardHSM(card);
		if (sc.verifyUserPIN() != 0x9000) {
			throw new Error("Wrong PIN. Login aborted");
		}
	}

	GPSystem.trace("Connect Card");
	card.remoteUpdate(conInfo.url, conInfo.sessionId);
	print("id  " + card.remoteMessageId);
	print("msg " + card.remoteMessage);

	if (login2) {
		var c = new URLConnection(baseURL);
		c.addHeaderField("Accept", "application/json");
		c.addHeaderField("Cookie", this.session);
		var result = c.get();
		print(result);
	}

	var sel = Dialog.prompt("Please remove the token to prevent accidently overwriting it");
	assert(sel, "User abort");
}



PortalPersonalizer.prototype.getDICA = function() {
	// Retrieve DICA

	var dicaURL = this.host + "/se/paas/subject-rest/" + this.subjectId + "/dica";

	var c = new URLConnection(dicaURL);
	c.addHeaderField("Cookie", this.session);
	var result = c.get();
	GPSystem.trace(result);

	var deviceIssuer = JSON.parse(result);
	var labels = [];
	for (var i = 0; i < deviceIssuer.dica.length; i++) {
	labels.push(deviceIssuer.dica[i].label);
	}

	var dicaLabel = Dialog.prompt("Select DICA", deviceIssuer.dica[0].label, labels);

	for (var i = 0; i < deviceIssuer.dica.length; i++) {
		var dica = deviceIssuer.dica[i];
		if (dica.label == dicaLabel) {
			this.dicaId = dica.id;
			print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
			print("You have selected the dica " + dicaLabel + " of Device Issuer "  + deviceIssuer.name + ".");
			print("Update your jobs.js configuration to the following to remember this decision for future use.");
			print("");
			print("PortalPersonalizer: {");
			print("\turl: \"" + this.host + "/se/paas/subject/" + this.subjectId + "\",");
			print("\tdicaId: " + this.dicaId);
			print("}");
			print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
		}
	}
}



PortalPersonalizer.prototype.createServiceRequest = function() {
	var srURL = this.host + "/se/paas/sr-rest/new";
	srURL += "?process=DICAPersonalization";
	srURL += "&ca=" + this.subjectId;
	srURL += "&dicaId=" + this.dicaId;
	if (typeof(this.job.hardware) != "undefined") {
		srURL += "&hardware=" + this.job.hardware;
	}
	if (typeof(this.job.kmc) != "undefined") {
		srURL += "&kmc=" + this.job.kmc;
	}

//	print("Post Personalization Request");

	var c = new URLConnection(srURL);
	c.addHeaderField("Cookie", this.session);
	var result = c.post("");
	if (c.responseCode != 201) {
		throw new GPError(module.id, GPError.OBJECTCREATIONFAILED, 0, "Failed to create personalization service request (" + c.responseCode + ")");
	}

	print(result);
	var rsp = JSON.parse(result);

	if (rsp.message != "msg.completed") {
		throw new GPError(module.id, GPError.OBJECTCREATIONFAILED, 0, "Failed to create personalization service request (" + rsp.detail + ")");
	}

	return rsp;
}



PortalPersonalizer.prototype.handleCard = function(card) {
	var sr = this.createServiceRequest();

	var remoteUpdateURL = sr.url;

	GPSystem.trace("Connect card to service request");
	card.remoteUpdate(remoteUpdateURL);

	if (card.remoteMessageId != 0) {
		throw new GPError(module.id, GPError.OBJECTCREATIONFAILED, 0, "Personalization service request failed: " + card.remoteMessage);
	}

	return "OK " + card.remoteMessage;
}
