/**
 *  ---------
 * |.##> <##.|  Open Smart Card Development Platform (www.openscdp.org)
 * |#       #|
 * |#       #|  Copyright (c) 2016 CardContact Systems GmbH
 * |'##> <##'|  Schuelerweg 38, 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 Plug-In Registry
 */

var File = require('scsh/file/File').File;



function PluginRegistry(service) {
	this.service = service;

	this.registry = [];
	this.registrymap = {};
	this.processFactories = {};
	this.subjectFactories = {};
	this.holderViewFactories = {};
}

exports.PluginRegistry = PluginRegistry;



PluginRegistry.prototype.sort = function() {
	this.registry.sort( function(a,b) { return a.priority - b.priority });
}



PluginRegistry.prototype.add = function(name, cfg, desc) {
	var exp = require(name);
	var p = new exp.Plugin(this.service, cfg, desc);

	this.registry.push(p);
	this.registrymap[p.toString()] = p;
}



PluginRegistry.prototype.detectPlugins = function(dir,cfg) {
	GPSystem.log(GPSystem.DEBUG, module.id, "dir: " + dir);
	var f = new File(dir);
	var l = f.list();
	for (var i = 0; i < l.length; i++) {
		var fn = l[i];
		if (fn.search(/.*-plugin\.js$/) == 0) {
			GPSystem.log(GPSystem.DEBUG, module.id, "Found : " + fn);
			fn = "plugins/" + fn.substr(0, fn.lastIndexOf("."));
			this.add(fn, cfg);
		}
	}
	for (var i = 0; i < l.length; i++) {
		var fn = l[i];
		if (fn.search(/.*\.json$/) == 0) {
			GPSystem.log(GPSystem.DEBUG, module.id, "Found : " + fn);
			fn = "plugins/" + fn;

			var jf = new File(fn);
			var s = jf.readAllAsString();
			jf.close();

			var desc = JSON.parse(s);
			this.add(desc.class, cfg, desc);
		}
	}
}



PluginRegistry.prototype.loadPlugins = function(cfg) {
	var dir = GPSystem.mapFilename("plugins", GPSystem.USR);
	this.detectPlugins(dir, cfg);
	this.sort();
}




PluginRegistry.prototype.getPlugin = function(name) {
	return this.registrymap[name];
}



PluginRegistry.prototype.enumerateRunnableProcesses = function(user) {
	var processes = [];

	for (var i = 0; i < this.registry.length; i++) {
		var p = this.registry[i];
		if (typeof(p.enumerateRunnableProcesses) == "function") {
			p.enumerateRunnableProcesses(user, processes);
		}
	}

	return processes;
}



PluginRegistry.prototype.enumerateRunnableProcessesForSubject = function(user, subject) {
	var processes = [];

	for (var i = 0; i < this.registry.length; i++) {
		var p = this.registry[i];
		if (typeof(p.enumerateRunnableProcessesForSubject) == "function") {
			p.enumerateRunnableProcessesForSubject(user, subject, processes);
		}
	}

	return processes;
}



PluginRegistry.prototype.enumerateRunnableProcessesForHolderType = function(user, subject, type) {
	var processes = [];

	for (var i = 0; i < this.registry.length; i++) {
		var p = this.registry[i];
		if (typeof(p.enumerateRunnableProcessesForHolderType) == "function") {
			p.enumerateRunnableProcessesForHolderType(user, subject, type, processes);
		}
	}

	return processes;
}



PluginRegistry.prototype.getFactoryForProcess = function(name) {
	if (typeof(this.processFactories[name]) != "undefined") {
		return this.processFactories[name];
	}
	for (var i = 0; i < this.registry.length; i++) {
		var p = this.registry[i];
		if (typeof(p.getFactoryForProcess) == "function") {
			GPSystem.log(GPSystem.DEBUG, module.id, "Found getFactoryForProcess in " + p);
			var f = p.getFactoryForProcess(name);
			if (f) {
				GPSystem.log(GPSystem.DEBUG, module.id, "Supports " + name);
				this.processFactories[name] = f;
				return f;
			}
		}
	}
	this.processFactories[name] = null;

	return undefined;
}



PluginRegistry.prototype.getFactoryForSubject = function(name) {
	if (typeof(this.subjectFactories[name]) != "undefined") {
		return this.subjectFactories[name];
	}
	for (var i = 0; i < this.registry.length; i++) {
		var p = this.registry[i];
		if (typeof(p.getFactoryForSubject) == "function") {
			GPSystem.log(GPSystem.DEBUG, module.id, "Found getFactoryForSubject in " + p);
			var f = p.getFactoryForSubject(name);
			if (f) {
				GPSystem.log(GPSystem.DEBUG, module.id, "Supports " + name);
				this.subjectFactories[name] = f;
				return f;
			}
		}
	}
	this.subjectFactories[name] = null;

	return undefined;
}



PluginRegistry.prototype.getFactoryForHolderType = function(type) {
	if (typeof(this.holderViewFactories[type]) != "undefined") {
		return this.holderViewFactories[type];
	}
	for (var i = 0; i < this.registry.length; i++) {
		var p = this.registry[i];
		if (typeof(p.getFactoryForHolderType) == "function") {
			GPSystem.log(GPSystem.DEBUG, module.id, "Found getFactoryForHolderType in " + p);
			var f = p.getFactoryForHolderType(type);
			if (f) {
				GPSystem.log(GPSystem.DEBUG, module.id, "Supports " + type);
				this.holderViewFactories[type] = f;
				return f;
			}
		}
	}
	this.holderViewFactories[type] = null;

	return undefined;
}
