package de.hsadmin.jscli;

import java.io.Reader;
import java.util.List;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class ScriptClient {

	private ScriptEngine engine;

	public ScriptClient(String user, String runAs) throws JSCliException {
		CASTicket grantingTicket = new CASTicket(user, runAs);
		RpcClient rpcClient = new RpcClient(grantingTicket);
		ScriptEngineManager engineManager = new ScriptEngineManager();
		engine = engineManager.getEngineByName("js");
		try {
			engine.put("casgrantingticket", grantingTicket);
			engine.put("xmlrpcclient", rpcClient);
			engine.eval("importClass(java.util.ArrayList);");
			engine.eval("importClass(java.util.HashMap);");
			engine.eval("function hsaParseParamArray(o) { " +
					"var lst = new ArrayList(); " +
					"var val = ''; " +
					"for (var idx=0; idx < o.length; idx++) { " +
					"  val = o[idx]; " +
					"  if (typeof val === 'object' && val.constructor === Array) { val = hsaParseParamArray(val); } " +
					"  else if (typeof val === 'object') { val = hsaParseParamObject(val); }; " +
					"  lst.add(val); " +
					"}; " +
					"return lst; " +
					"}");
			engine.eval("function hsaParseParamObject(o) { " +
					"var hsh = new HashMap(); " +
					"for (var key in o) { " +
					"  var val = o[key]; " +
					"  if (typeof val === 'object' && val.constructor === Array) { val = hsaParseParamArray(val); } " +
					"  else if (typeof val === 'object') { val = hsaParseParamObject(val); }; " +
					"  hsh.put(key, val); " +
					"}; " +
					"return hsh; " +
					"};");
		} catch (ScriptException e) {
			throw new JSCliException(e);
		}
		List<String> methods = rpcClient.listMethods();
		for (String method : methods) {
			String[] parts = method.split("\\.");
			if (parts.length == 2) {
				String module = parts[0];
				String function = parts[1];
				if ("delete".equals(function)) {
					function = "remove";
				}
				try {
					engine.eval("if (typeof " + module + " === 'undefined') " +
								"{ var " + module + " = { }; };\n" +
								module + "['" + function + "'] = function(json) { " +
								"var mod = '" + module + "'; " +
								("remove".equals(function) ? "var fct = 'delete'; " : "var fct = '" + function + "'; ") +
								"var params = new ArrayList(); " +
								"params.add(casgrantingticket.getRunAs()); " + 
								"params.add(casgrantingticket.getTicket()); " + 
								"if (typeof json === 'undefined') { json = { where:{}, set:{} } };" +
								"if (fct == 'update' || fct == 'add') { params.add(hsaParseParamObject(json['set'])); }; " + 
								"if (fct == 'update' || fct == 'delete' || fct == 'search') { params.add(hsaParseParamObject(json['where'])); }; " + 
								"return xmlrpcclient.execute(mod + '.' + fct, params); " + 
								"};");
				} catch (ScriptException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public Object execute(String snippet) throws JSCliException {
		try {
			return engine.eval(snippet);
		} catch (ScriptException e) {
			throw new JSCliException(e);
		}
	}
	
	public Object execute(Reader rd) throws JSCliException {
		try {
			return engine.eval(rd);
		} catch (ScriptException e) {
			throw new JSCliException(e);
		}
	}
	
}
