/*
 *	IT-Services der Sozialversicherung GmbH
 *	Software Operations
 *	Software Quality Assurance
 *
 *	PRODUCT:	CCDB - Competence Center Database
 *	MODULE:		queryparamforms.js
 *	VERSION:	0.8.0.99
 *	AUTHOR:		WSC - Wolfgang Scherer
 *	HISTORY:
 *  Version    | Date       | Description
 * ------------+------------+---------------------------------------------------
 * 00.08.00.99 | 2015-11-30 | Created for editing query parameters
 * ------------+------------+---------------------------------------------------
 * 00.08.01.00 | 2017-11-22 | add 'fileupload' input
 * ------------+------------+---------------------------------------------------
 *
 */
 
console.log("queryparamforms loaded");

var queryparamforms_version = '00.08.00.99';

var forms = {};

// synchronization of text input and drop-down select for 'presets' input
function combo(thelist, theinput) {
    theinput = document.getElementById(theinput);
    var idx = thelist.selectedIndex;
    var content = thelist.options[idx].innerHTML;
    theinput.value = content;
}

//
// ============ Legacy Support for Version below 00.08 =========================
//
function addAttributeLine(theTableId) {
	thetable = document.getElementById(theTableId)
	newRow = thetable.insertRow(-1);
	labCell = newRow.insertCell(-1);
	valCell = newRow.insertCell(-1);
	labCell.innerHTML = "neue Label-Zelle";
	valCell.innerHTML = "neue Werte-Zelle";
}

// make <o> to something displayable
function makeString(o) {
	var ts = typeof o;
	switch (ts) {
		case 'number':
		case 'string':
		case 'boolean':
			return o;
			break;
		default:
			return '['+ts+']';
	}
}

// create a visual presentation of <obj> and insert it into <parent>
function insert_doctable(parent,obj) {
	var ftab;
	var tn;
	if (typeof obj === 'object') {
		ftab = document.createElement('table');
		ftab.style.border = "1px solid black";
		ftab.style.borderCollapse = "collapse";
		var frow = ftab.insertRow(-1);
		var fnc = frow.insertCell(-1);
		var fvc = frow.insertCell(-1);
		tn = document.createTextNode("Name");
		fnc.style.fontWeight = "bold";
		fnc.style.border = "1px solid black";
		fvc.style.border = "1px solid black";
		fnc.appendChild(tn);
		tn = document.createTextNode("Wert");
		fvc.style.fontWeight = "bold";
		fvc.appendChild(tn);
		for (fd in obj) {
			frow = ftab.insertRow(-1);
			fnc  = frow.insertCell(-1);
			fvc  = frow.insertCell(-1);
			fnc.style.border = "1px solid black";
			fvc.style.border = "1px solid black";
			fnc.style.verticalAlign = "top";
			fnc.appendChild(document.createTextNode(fd));
			insert_doctable(fvc,obj[fd]);
		}
	} else {
		ftab = document.createElement('p');
		tn = document.createTextNode(makeString(obj));
		ftab.appendChild(tn);
	}
	parent.appendChild(ftab);
}	

//
// =========================== forms handling ==================================================
//

//
// anchor elements provide the link between the DOM and the formdata structure(s)
//
var anchorElements = {};

/*
 *	FUNCTION:	createAnchorElement
 *	INPUT:		etyp	-	HTML element type string 
 *				fdo		-	the forms data object in the forms data object tree got from the server
 *							this is a reference to a [paraminfo] object
 *				eid		-	the ID the HTML element created shall receive
 *	RETURNS:	aeo	-	anchor element object:
 *					id	- 	the DOM ID of the created HTML element / anchor element for <fdo>
 *							this is usually equal to <eid>, but should not be depended on
 *					el	-	DOM handle to created element
 *					ael	-	handle to anchor element
 *	DESCRIPTION:	creates an HTML element with its according entry in the <anchorElements> dictionary
 *					this allow to find the forms data entry in element event handling functions
 */
function createAnchorElement(etyp,fdo,eid) {
	var el = document.createElement(etyp);
	el.setAttribute("id",eid);
	if (anchorElements[eid]) {
		console.error("AnchorElementsError: element with ID "+eid+" already existing anchor element");
	}
	anchorElements[eid] = {};					// create the anchor element with the name <eid>
	anchorElements[eid].dataobject = fdo;
	return {id: eid, el: el, ael: anchorElements[eid]};
}

function getAnchorElement(id) {
	if (!anchorElements[id]) {
		console.error("AnchorElementsError: there is no anchor element with id "+id);
		console.log("Present anchor elements are: ",anchorElements);
	}
	return anchorElements[id];
}

//
// atomic inputs 
//
function newArrayLine(inpid) {
	var inp = document.getElementById(inpid);
	var ael = getAnchorElement(inpid);
	if (ael.paraminfo) {
		var nr = createObjectInput(ael.formid,ael.paraminfo,inpid+"."+ael.tablength,{ignorebasename: true});
		ael.atable.appendChild(nr);
		ael.tablength++;
	} else {
		console.error("Element "+inpid+" has no paraminfo");
	}
}

function createNumberInput(formid,pdo,idprefix) {
	var myid = idprefix+"."+pdo.name;
	var aeo = createAnchorElement('input',pdo,myid);
	aeo.el.setAttribute("type","number");
	aeo.el.setAttribute("name",myid);
	aeo.ael.paraminfo = pdo;
	aeo.ael.formid = formid;
	aeo.ael.idprefix = idprefix;
	if (pdo.value) {
		if (typeof(pdo.value)==='number') {
			aeo.el.setAttribute("value",pdo.value);
		} else {
			console.error("Illegal value type "+typeof(pdo.value)+" for number input: ",pdo.value);
		}
	}
	return aeo.el;
}

function createFileUploadInput(formid,pdo,idprefix) {
	myid = idprefix+'.'+pdo.name;
	var aeo = createAnchorElement('input',pdo,myid);
	aeo.el.setAttribute("type","file");
	aeo.el.setAttribute("name",myid);
	aeo.ael.paraminfo = pdo;
	aeo.ael.formid = formid;
	aeo.ael.idprefix = idprefix;
	return aeo.el;
}

function createStringInput(formid,pdo,idprefix) {
	myid = idprefix+'.'+pdo.name;
	var aeo = createAnchorElement('input',pdo,myid);
	aeo.el.setAttribute("type","text");
	aeo.el.setAttribute("name",myid);
	aeo.ael.paraminfo = pdo;
	aeo.ael.formid = formid;
	aeo.ael.idprefix = idprefix;
	if (pdo.maxlen) aeo.el.setAttribute("size",pdo.maxlen);
	if (pdo.value) {
		if (typeof(pdo.value)==='string') {
			aeo.el.setAttribute("value",pdo.value);
		} else {
			console.error("Illegal value type "+typeof(pdo.value)+" for string input: ",pdo.value);
		}
	}
	return aeo.el;
}

/* ******************************************************************************************
 *		FUNCTION:		createEnumInput
 *		INPUT:			formid		-	unique ID of the form this Enum is part of
 *						pdo			-	paramdata object containing control information for the enum input
 *						idprefix	-	unique prefix to prepend to the ID of the input element
 *		RESULT:			html DOM element created
 *		DESCRIPTION:	creates an OPTION html element to allow selection of enum data points
 *						the "name" attribute of the input element will be set to <idprefix>.<pdo.name>
 *						<pdo> is expected to have the following attributes:
 *							.name	-	a unique name for this element inside the form it belongs to
 *							.vlist	-	an array of object with the selectable data points
 *										these are expected to have:
 *										.text	-	the text to present to the user
 *										.value	-	used to set the "value" attribute of the option
 *													this will be the value of the form item
 *										.desc	-	used to set the "title" attribute of the option
 *													this will show in the tooltip of the option
 *						An Anchor element will be created in order to navigate form the DOM element
 *						to the PDO and vice versa
 */
function createEnumInput(formid,pdo,idprefix) {
	var opt;
	var optxt;
	var myid = idprefix+"."+pdo.name;
	var aeo = createAnchorElement("select",pdo,myid);
	aeo.ael.paraminfo = pdo;
	aeo.ael.formid = formid;
	aeo.ael.idprefix = idprefix;
	aeo.el.setAttribute("name",myid);
	for (vle in pdo.vlist) {
		opt = document.createElement("option");
		optxt = document.createTextNode(pdo.vlist[vle].text);
		opt.setAttribute("value",pdo.vlist[vle].value);
		opt.setAttribute("title",pdo.vlist[vle].desc);
		if (pdo.vlist[vle].selected) opt.setAttribute("selected","");
		opt.appendChild(optxt);
		aeo.el.appendChild(opt);
	}
	return aeo.el;
}

function createPresetsInput(formid,pdo,idprefix) {
	var opt;
	var optxt;
	var myid = idprefix+'.'+pdo.name;
	var aeo = createAnchorElement("fieldset",pdo,myid);
	aeo.ael.paraminfo = pdo;
	aeo.ael.formid = formid;
	aeo.ael.idprefix = idprefix;
	aeo.el.setAttribute("id",myid+"_set");
	var txi = document.createElement("input");
	txi.setAttribute("id",myid);
	txi.setAttribute("name",myid);
	var sel = document.createElement("select");
	sel.setAttribute("id",myid+"_sel");
	for (vle in pdo.vlist) {
		opt = document.createElement("option");
		optxt = document.createTextNode(pdo.vlist[vle].text);
		opt.setAttribute("value",pdo.vlist[vle].value);
		opt.setAttribute("title",pdo.vlist[vle].desc);
		opt.setAttribute("id",myid+"_opt_"+pdo.vlist[vle].value);
		if (pdo.vlist[vle].selected) opt.setAttribute("selected","");
		opt.appendChild(optxt);
		sel.appendChild(opt);
	}
	sel.setAttribute("onChange","combo(this,\""+myid+"\")");
	return aeo.el;
}

// create an input element to enter data for an array
function createArrayInput(formid,pdo,idprefix) {
	var myid = idprefix+"."+pdo.name;								// myid is the ID of the whole array input, which is no input in its own right (contains only other inputs)	
	var aeo = createAnchorElement('fieldset',pdo,myid);				// ... instead, myid identifies the fieldset encompassing all inputs for the array
	aeo.ael.paraminfo = pdo;
	aeo.ael.formid = formid;
	aeo.ael.idprefix = idprefix;
	var atab = document.createElement('table');						// atab is a table having one row for each row in the array ...
	aeo.ael.atable = atab;
	aeo.ael.tablength = 0;
	atab.setAttribute("id",myid+"_table");
	var r = atab.insertRow(0);										// ... plus one header row with an "Add new row" button
	var c = r.insertCell(0);
	var newbut = document.createElement('button');
	newbut.appendChild(document.createTextNode("Neue Zeile"));
	newbut.setAttribute("id",myid+"_newbutton");
	newbut.setAttribute("OnClick","newArrayLine(\""+myid+"\")");
	newbut.setAttribute("type","button");
	c.appendChild(newbut);
	aeo.el.appendChild(atab);
	if (pdo.value) {
		console.log("Array Input has value assigned in fdata, although representation is not yet defined: ",pdo.value);
	// TODO: fill in pre-set value(s). 
	// NB: in principle, each entry in <.paramdata> has its own value attribute.
	//		However, this could carry only one value, but we'd need one per row !
	}
	return aeo.el;
}

// create an input element to enter data for an object
function createObjectInput(formid,pdo,idprefix,options) {
	var myid;
	if (options && options.ignorebasename) {
		myid = idprefix;	// special case: if caller requests, the base name is not included in the name hierarchy (e.g. if this object is entry in an array
	} else {
		myid = (pdo.name)?(idprefix+"."+pdo.name):(idprefix);	// myid is the ID of the whole object input, which is no input in its own right (contains only other inputs)
						// special situation: if pdo.name does not exist, this is the top level form and does not need deeper level in ids
	}
	console.log("createObjectInput.ID="+myid);
	var aeo = createAnchorElement('fieldset',pdo,myid);			// ... instead, myid identifies the fieldset encompassing all inputs for the object
	aeo.ael.paraminfo = pdo;
	aeo.ael.formid = formid;
	aeo.ael.idprefix = idprefix;
	var atab = document.createElement('table');
	aeo.el.appendChild(atab);
	aeo.ael.atable = atab;
	var nr;
	for (var oai=0; oai<pdo.paramdata.length; oai++) {
		nr = createFormInput(formid,pdo.paramdata[oai],myid);
		atab.appendChild(nr);
	}
	if (pdo.value) {
		console.warn("Object Input has value, which is not defined (each field shall have its value)!");
	}
	return aeo.el;
}	
	

// create the input elements for one parameter object <pdo> into <parent>
// <pdo> is assumed to be a [paraminfo] object
// returns a <tr> element to be appended to a table
function createFormInput(formid,pdo,idprefix) {
	console.log("createFormInput.name="+idprefix+'.'+pdo.name);
	var tr = document.createElement('tr');
	// first the label
	var lab = document.createElement('label');
	var ltx = document.createTextNode(pdo.attributes?pdo.attributes.labeltext:null || pdo.labeltext || pdo.typetext || pdo.name);
	lab.setAttribute("title",pdo.attributes?pdo.attributes.typedesc:null || pdo.typedesc);
	lab.appendChild(ltx);
	// then the input(s) for the value
	var inp = null;
	if (pdo.inputString) {
		inp = createStringInput(formid,pdo,idprefix);
	} else if (pdo.inputNumber) {
		inp = createNumberInput(formid,pdo,idprefix);
	} else if (pdo.inputEnum) {
		inp = createEnumInput(formid,pdo,idprefix);
	} else if (pdo.inputPresets) {
		inp = createPresetsInput(formid,pdo,idprefix);
	} else if (pdo.inputArray) {
		inp = createArrayInput(formid,pdo,idprefix);
	} else if (pdo.inputObject) {
		inp = createObjectInput(formid,pdo,idprefix);
	} else if (pdo.inputFileUpload) {
		inp = createFileUploadInput(formid,pdo,idprefix);
	} else {
		console.error("undefined input type of "+pdo.name+":",pdo);
	}
	var lc = tr.insertCell(0);
	lc.appendChild(lab);
	var vc = tr.insertCell(-1);
	vc.appendChild(inp);
	return tr;
}

// build up the html for the form
// ATTENTION: as of Version 0.8.1 and below, only one form with the same dataname may exist on one page !! 
//            this is because: 
//	INPUT:		fdata		-	a [paramdata] object defining the properties of the form to be generated
//				formid		-	the DOM-ID of an element that shall contain the built form
//				doctableid	-	
//	GLOBALS:	forms		-	a collection object for all forms created by this function
function build_form(fdata,formid,doctableid) {
	var f = document.getElementById(formid);
	forms[formid] = {};
	forms[formid].fdata = fdata;
	var dt = document.getElementById(doctableid);
	console.log("build_form.fdata: ",fdata);
	// insert_doctable(dt,fdata);
	var form = document.createElement('form');
	form.setAttribute("enctype","multipart/form-data");
	form.setAttribute("action",fdata.url);
	form.setAttribute("method","POST");
	form.setAttribute("id",formid);
	var submitbutton = document.createElement("input");
	submitbutton.setAttribute("type","submit");
	submitbutton.setAttribute("id",formid+"_submit");
	submitbutton.setAttribute("value",(fdata.reqtype?fdata.reqtype:"Aktion")+" starten");
	form.appendChild(submitbutton);
	if (fdata.dataname) {
		var dnf = document.createElement("input");
		dnf.setAttribute("type","hidden");
		dnf.setAttribute("id","dataname");
		dnf.setAttribute("name",formid+".dataname");
		dnf.setAttribute("value",fdata.dataname);
		form.appendChild(dnf);
	}
	// console.log("fdata: ",fdata);
	var fp = createObjectInput(formid,fdata,formid);
	form.appendChild(fp);
	f.appendChild(form);
}
