/**
 *  ---------
 * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
 * |#       #|
 * |#       #|  Copyright (c) 1999-2018 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 Service request model role management
 */

var ServiceRequestModel		= require('pki-as-a-service/service/ServiceRequestModel').ServiceRequestModel;



/**
 * Data model for requesting a certificate
 *
 *
 * @constructor
 */
function ManageRoleServiceRequestModel(service, bo) {
	ServiceRequestModel.call(this, service, bo);
	this.validationResult = [];
}

ManageRoleServiceRequestModel.prototype = Object.create(ServiceRequestModel.prototype);
ManageRoleServiceRequestModel.constructor = ManageRoleServiceRequestModel;

exports.ManageRoleServiceRequestModel = ManageRoleServiceRequestModel;



ManageRoleServiceRequestModel.prototype.getAssignableRoles = function() {
	var roleDAO = this.service.daof.getRoleDAO();

	var roleList = [];
	var assignableRoles = roleDAO.getManagedRoles(this.getOriginatorId());
	var recipientRoles = roleDAO.getAssignedRoleIds(this.getRecipientId());

	for (var i = 0; i < assignableRoles.length; i++) {
		var assignableRole = assignableRoles[i];
		if (recipientRoles.indexOf(assignableRole.id) == -1) {
			roleList.push(assignableRole);
		}
	}

	return roleList;
}



ManageRoleServiceRequestModel.prototype.getRemovableRoles = function() {
	var roleDAO = this.service.daof.getRoleDAO();

	var roleList = [];
	var assignableRoles = roleDAO.getManagedRoles(this.getOriginatorId());
	var recipientRoles = roleDAO.getAssignedRoleIds(this.getRecipientId());

	for (var i = 0; i < assignableRoles.length; i++) {
		var assignableRole = assignableRoles[i];
		if (recipientRoles.indexOf(assignableRole.id) >= 0) {
			roleList.push(assignableRole);
		}
	}

	return roleList;
}



ManageRoleServiceRequestModel.prototype.assignSelectedRoles = function() {
	GPSystem.log(GPSystem.DEBUG, module.id, "assignSelectedRoles(" + this.model.assignRoles + ")");
	var roleDAO = this.service.daof.getRoleDAO();
	for (var i = 0; i < this.model.assignRoles.length; i++) {
		var roleId = this.model.assignRoles[i];
		roleDAO.newAssignedRole(this.getRecipientId(), roleId, this.bo.id);
	}
}



ManageRoleServiceRequestModel.prototype.revokeSelectedRoles = function() {
	GPSystem.log(GPSystem.DEBUG, module.id, "revokeSelectedRoles(" + this.model.removeRoles + ")");
	var roleDAO = this.service.daof.getRoleDAO();
	for (var i = 0; i < this.model.removeRoles.length; i++) {
		var roleId = this.model.removeRoles[i];
		roleDAO.deleteAssignedRole(this.getRecipientId(), roleId);
	}
}



ManageRoleServiceRequestModel.prototype.getForm = function(user) {
	if (this.form == undefined) {

		if (!this.model.assignRoles) {
			this.model.assignRoles = []
		}
		if (!this.model.removeRoles) {
			this.model.removeRoles = []
		}

		var subjectField = { id: "subject", label: "msg.mr.id", type: "text", size: 50, required: true, editable: false, value: this.getRecipientId() };

		if (this.bo.lifecycle < ServiceRequestModel.LIFECYCLE_COMPLETE) {
			var assignEditable = user.id == this.getOriginatorId();
			var removeEditable = assignEditable;

			var roles = this.getAssignableRoles();
			var assignableRoleList = [];
			for (var i = 0; i < roles.length; i++) {
				var role = roles[i];

				var e = { id: role.id, value: role.name };
				if (this.model.assignRoles.indexOf(role.id) >= 0) {
					e.selected = true;
				}
				assignableRoleList.push(e);
			}

			if (assignableRoleList.length == 0) {
				assignableRoleList.push( {id: 1, msg: "msg.mr.noAssignableRoles"} );
				assignEditable = false;
			}

			var roles = this.getRemovableRoles();
			var removableRoleList = [];
			for (var i = 0; i < roles.length; i++) {
				var role = roles[i];

				var e = { id: role.id, value: role.name };
				if (this.model.removeRoles.indexOf(role.id) >= 0) {
					e.selected = true;
				}
				removableRoleList.push(e);
			}

			if (removableRoleList.length == 0) {
				removableRoleList.push( {id: 1, msg: "msg.mr.noRemovableRoles"} );
				removeEditable = false;
			}

			this.form = [
				{
					id: "applicant",
					legend: "msg.mr.subject",
					fields: [subjectField]
				},
				{
					id: "applicant",
					legend: "msg.mr.assign",
					fields: [{ id: "assignRoles", label: "msg.mr.roles", type: "select", multiselect: true, editable: assignEditable, value: assignableRoleList }]
				},
				{
					id: "applicant",
					legend: "msg.mr.remove",
					fields: [{ id: "removeRoles", label: "msg.mr.roles", type: "select", multiselect: true, editable: removeEditable, value: removableRoleList }]
				}
			];
		} else {
			this.form = [{
					id: "applicant",
					legend: "msg.mr.subject",
					fields: [subjectField]
				}];

			if (this.model.assignRoles.length > 0) {
				var roleDAO = this.service.daof.getRoleDAO();
				var assignedList = [];
				for (var i = 0; i < this.model.assignRoles.length; i++) {
					var id = this.model.assignRoles[i];
					var role = roleDAO.getRoleById(id);
					assignedList.push( { id: role.id, value: role.name} );
				}
				this.form.push({
						id: "applicant",
						legend: "msg.mr.assigned",
						fields: [ { id: "assignRoles", label: "msg.mr.roles", type: "select", multiselect: true, editable: false, required: true, value: assignedList } ]
					}
				);
			}

			if (this.model.removeRoles.length > 0) {
				var roleDAO = this.service.daof.getRoleDAO();
				var removedList = [];
				for (var i = 0; i < this.model.removeRoles.length; i++) {
					var id = this.model.removeRoles[i];
					var role = roleDAO.getRoleById(id);
					removedList.push( { id: role.id, value: role.name} );
				}
				this.form.push({
						id: "applicant",
						legend: "msg.mr.removed",
						fields: [ { id: "removeRoles", label: "msg.mr.roles", type: "select", multiselect: true, editable: false, required: true, value: removedList } ]
					}
				);
			}
		}

	}

	return this.form;
}



ManageRoleServiceRequestModel.prototype.getActionList = function(user) {
	if (this.actionList != undefined) {
		return this.actionList;
	}

	this.actionList = [];

	if (user.id == this.getOriginatorId()) {
		if ((this.bo.lifecycle == ServiceRequestModel.LIFECYCLE_NEW) || (this.bo.lifecycle == ServiceRequestModel.LIFECYCLE_EDIT)) {
			if (this.getAssignableRoles().length > 0 ||this.getRemovableRoles().length > 0) {
				this.actionList.push("action.save");
			}
		}

		if (this.bo.lifecycle == ServiceRequestModel.LIFECYCLE_EDIT
			&& (this.model.assignRoles.length > 0 || this.model.removeRoles.length > 0)) {
			this.actionList.push("action.apply");
		}
	}

	return this.actionList;
}



ManageRoleServiceRequestModel.prototype.perform = function(user, action) {
	GPSystem.log(GPSystem.DEBUG, module.id, "perform(" + user.id + "," + action + ")");

	var actionList = this.getActionList(user);

	if (actionList.indexOf(action) == -1) {
		throw new GPError(module.id, GPError.INVALID_DATA, 0, "Action " + action + " unknown");
	}

	switch(action) {
		case "action.save":
			if (this.getLifeCycle() == ServiceRequestModel.LIFECYCLE_NEW) {
				this.setLifeCycle(ServiceRequestModel.LIFECYCLE_EDIT);
				this.setStatusInfo("Request data entered");
			}
			break;
		case "action.apply":
			this.assignSelectedRoles();
			this.revokeSelectedRoles();
			this.model.selectedRoles = [];
			this.setLifeCycle(ServiceRequestModel.LIFECYCLE_COMPLETE);
			this.setStatusInfo("Subject roles updated");
			break;
	}

	this.commit(user.id);
	return true;
}
