//global config variable
const config=new Object();

function print(msg){
	config.document.getElementById(config.debugArea).value+="\n"+msg;
}

function clear(){
	config.document.getElementById(config.debugArea).value="";
}

function doNothing(){
	print('doNothing called');
}


function generateDescription(){
	//loop over all forms
	//read the setup
	print('Generate description');
	setFormConfig();
	
}

function setContainer(label,container){
	if (!(config.formConfig.hasOwnProperty('container'))){
		config.formConfig.container=new Array();
	}
	config.formConfig.container[label]=container;
}

function getContainer(label){
	return config.formConfig.container[label];
}

function makeQuery(containerName,queryName,fieldName,filterArray){
	let e=new Object();
	e.containerName=containerName;
	e.queryName=queryName;
	e.fieldName=fieldName;
	e.filterArray=filterArray;
	return e;
}



function getDataFromQueries(queryArray,cb){
	//queryArray should contain elements with
	//- fieldName to set the data variable
	//- containerName to select container (data,config,CRF)
	//- queryName to select query
	//- filterArray to perform filtering, empty array works
	//- callback cb to be called with no arguments
	//
	afterQuery(new Object(),-1,queryArray,cb);
}


function afterQuery(data,id,queryArray,cb){
	//queryArray should contain elements with
	//- fieldName to set the data variable
	//- containerName to select container (data,config,CRF)
	//- queryName to select query
	//- filterArray to perform filtering, empty array works
	//- callback cb to be called with no arguments
	//
	//it should be called with id -1.
	//
	print('afterQuery['+id+'/'+queryArray.length+']: ');

	if (id>-1){
		let fieldName=queryArray[id].fieldName;
		print('afterQuery['+fieldName+']: '+data.rows.length);
		config.formConfig[fieldName]=data;
	}
	id+=1;
	if (id==queryArray.length) {
		cb();
		return;
	}


	let e=queryArray[id];
	let qconfig=new Object();
	qconfig.containerPath=getContainer(e.containerName);
	qconfig.schemaName="lists";
	if ("schemaName" in e){
		print('afterQuery: schemaName='+e.schemaName);
		qconfig.schemaName=e.schemaName;
	}

	if ("columns" in e){
		print('afterQuery: columns='+e.columns);
		qconfig.columns=e.columns;
	}
	qconfig.queryName=e.queryName;
	//this should point to configuration container
	//don't filter -> so we can pick up other forms (say registration) later on
	//qconfig.filterArray=[LABKEY.Filter.create('Key',config.formId)];
	if ("filterArray" in e)
		qconfig.filterArray=e.filterArray;
	
	//qconfig.filterArray=[LABKEY.Filter.create('formStatus',1)]
	qconfig.success=function(data){afterQuery(data,id,queryArray,cb);};
	qconfig.failure=doNothing;
	LABKEY.Query.selectRows(qconfig);

}

function setFormConfig(){

	

	//add object to store form related data
	config.formConfig=new Object();

	config.formConfig.softwareVersion='0.0.1';
	let debug=true;

	if (debug)
		print("setFormConfig");	
	
	//set containers for data and configuration

	//TODO: set this from a query
	//
	
	setContainer('data',LABKEY.ActionURL.getContainer());
	setContainer('config',LABKEY.ActionURL.getContainer());
	setContainer('CRF',LABKEY.ActionURL.getContainer());

	let selectRows=new Object();
	//this is local data
	selectRows.containerPath=getContainer('CRF');
	selectRows.schemaName='lists';
	selectRows.queryName='crfSettings';
	//store form related data to this object
	selectRows.success=afterSettings;
	LABKEY.Query.selectRows(selectRows);

}

function afterSettings(data){

	config.formConfig.settings=new Array();
	for (let i=0;i<data.rows.length;i++){
		let n=data.rows[i]['name'];
		let v=data.rows[i]['value'];
		config.formConfig.settings[n]=v;
	}

	let st=config.formConfig.settings;
	print('afterSettings');
	for (let k in st){
		print('\t'+k+'='+st[k]);
	}

	//if ('dataContainer' in st){
	//	setContainer('data',st['dataContainer']);
	//}
	let vname='configContainer';
	if (vname in st){
		setContainer('config',st[vname]);
	}
	print('Config: '+getContainer('config'));
	print('Data: '+getContainer('data'));
	collectData();
}


function collectData(){

	let queryArray=new Array();
	//users
	queryArray.push(makeQuery('CRF','users','userData',[]));
	queryArray[queryArray.length-1].schemaName='core';
	
	//Forms	
	queryArray.push(makeQuery('config','Forms','formData',[]));
	//FormSetup	
	queryArray.push(makeQuery('config','FormSetup','formSetup',[]));
	//inputLists
	queryArray.push(makeQuery('config','inputLists','inputLists',[]));
	//

	print('running getDataFromQueries');
	getDataFromQueries(queryArray,fcontinue);
}

function findName(listId){
	let frows=config.formConfig.inputLists.rows;
	for (let i=0;i<frows.length;i++){
		if (frows[i]['Key']!=listId) continue;
		return frows[i]['queryName'];
	}
}

function fcontinue(){
	print('loadedData');
	let queryArray=new Array();
	
	let frows=config.formConfig.formSetup.rows;
	for (let i=0;i<frows.length;i++){
		let listId=frows[i]['queryName'];
		//skip forms only
		let showFlag=frows[i]['showFlag'];
		let showQuery=frows[i]['showQuery'];
		if (showFlag=='REVIEW') continue;
		let listName=findName(listId);
		print(listName);
		queryArray.push(makeQuery('data',listName,listName,[]));
		if (showFlag=='NONE') continue;
		queryArray.push(makeQuery('data',showQuery,showQuery,[]));
	}

	getDataFromQueries(queryArray,fcontinue1);

}

function getList(formId){
	let fList=new Array();
	let frows=config.formConfig.formSetup.rows;
	for (let i=0;i<frows.length;i++){
		if (frows[i]['formName']!=formId) continue;
		let listId=frows[i]['queryName'];
		let showFlag=frows[i]['showFlag'];
		let showQuery=frows[i]['showQuery'];
		if (showFlag=='REVIEW') continue;
		let fObj=new Object();
		fObj['queryName']=findName(listId);
		fObj['title']=frows[i]['title'];
		fList.push(fObj);
		if (showFlag=='NONE') continue;
		let fObj1=new Object();
		fObj1['queryName']=showQuery;
		fObj1['title']=frows[i]['title']+' (details)';
		fList.push(fObj1);
	}
	return fList;
}

function printField(field){
	let name=field['name'];
	if (name=='Key') return;
	if (name=='crfRef') return;
	let type=field['type'];
	let qName='';
	if ('lookup' in field){
		qName=field.lookup.queryName;
	}
	print(name+' '+type+'/'+qName);
	printPDF(field);
}

function addLookup(lookupList,field){
	if ('lookup' in field){
		lookupList.add(field.lookup.queryName);
	}
}

function printFields(lookupList,listName){
	let fields=config.formConfig[listName].metaData.fields;
	//print('getFields '+listName+': '+fields.length);
	for (f in fields){
		printField(fields[f]);
		addLookup(lookupList,fields[f]);		
		//printPDF(fields[f]);
	}
}

function fcontinue1(){
	printLayout();
}

function printData(){
	let frows=config.formConfig.formData.rows;
	let lookupList=new Set();
	for (let i=0;i<frows.length;i++){
		let formId=frows[i]['Key'];
		print(frows[i]['formName']);
		printTitlePDF(20,frows[i]['formName']);
		let fList=getList(formId);
		for (let j=0;j<fList.length;j++){
			print(fList[j]['queryName']);
			printTitlePDF(16,fList[j]['title']);
			printFields(lookupList,fList[j]['queryName']);
		}
	}
	print('all done');
	let queryArray=new Array();
	for (let item of lookupList){
		queryArray.push(makeQuery('data',item,item,[]));
	}
	let cb=function(){printLookup(lookupList);};
	getDataFromQueries(queryArray,cb);
}

function printQuery(queryName){
	printTitlePDF(16,queryName);
	print(queryName);
	let frows=config.formConfig[queryName].rows;
	print('rows: '+frows);
	let fields=config.formConfig[queryName].metaData.fields;
	let field=undefined;
	for (f in fields){
		if (fields[f].name=='Key') continue;
		field=fields[f];
		break;
	}
	for (let i=0;i<frows.length;i++){
		printPDFEntry(field,frows[i]);
	}
}

function printLookup(lookupList){

	printTitlePDF(20,'Enumerators');
	for (let item of lookupList){
		printQuery(item);
	}
	config.doc.end();

}

function checkBlob(){
	print("checkBlob: "+config.blob);
	if (config.blob) {
		clearInterval(config.blobInterval);
		config.a.href = config.window.URL.createObjectURL(config.blob);
		print("HREF: "+config.a.href);
		config.a.download = 'test.pdf';
		config.a.click();
		config.window.URL.revokeObjectURL(config.a.href);
	}
	config.count=config.count+1;
	print("Eval: "+config.count);
	if (config.count>100){
		clearInterval(config.blobInterval);
	}

}


function printLayout(){

	config.doc=new PDFDocument();
	//config.doc.end();
	let stream = config.doc.pipe(blobStream()).on("finish",function(){
			config.blob=stream.toBlob("application/pdf");});
	
	print("BLob: "+config.blob);
	config.a = config.document.createElement("a");
	config.document.body.appendChild(config.a);
	config.a.innerHTML="Download PDF";
	config.a.style = "display: none";
	config.count=0;
	//run until blob is set
	config.blobInterval=setInterval(checkBlob,1000);

	//pick data from crfForm list
        print("Printing form");
	printData();
}

function printTitlePDF(fontSize,title){
	config.doc.y+=10;
	config.doc.font('Courier-Bold').fontSize(fontSize).text(title);
}

function printPDF(field){
	//object field should have a name, type, caption
	//entry should have field.name
	//lookup is null or has a lookup table LUT 
	//for value v of entry[field.name]
	//
	//the total width of a A4 page is 598 px, 
	//left margin is 72. With a right margin of 50,
	//the total available with is 476 px.
	
	let w=476;
	let spacing=25;
	let w1=(w-spacing)*0.5;
	let fontSize=14;	
	
	print('printPDF: entry['+field.name);
	print('printPDF: field type:'+field.type);

	//measure text
	let label=field.caption;
	let opt={width:w1};
	config.doc.fontSize(fontSize);
	
	//for more eloquent display the height of the text
	//can be measured prior to output
	//use currentLineHeight to scale height
	//let lineH=config.doc.currentLineHeight(1);
	//let h=config.doc.heightOfString(label,opt)/lineH;


	//print label
	config.doc.font('Courier').text(label,opt);
	
	//align last row of description w/ first row of value
	config.doc.moveUp();

	//store x value for later use
	let tx=config.doc.x;
	let ty=config.doc.y;

	//shift for value output
	config.doc.x+=w1+spacing;
	let v=field.type;
	if ('lookup' in field){
		v+='/'+field.lookup.queryName;
	}
	print('v: '+v);
	config.doc.font('Courier-Bold').text(v,opt);

	//restore x value
	config.doc.x=tx;
	
}

function printPDFEntry(field,entry){
	//object field should have a name, type, caption
	//entry should have field.name
	//lookup is null or has a lookup table LUT 
	//for value v of entry[field.name]
	//
	//the total width of a A4 page is 598 px, 
	//left margin is 72. With a right margin of 50,
	//the total available with is 476 px.
	
	let w=476;
	let spacing=25;
	let w1=(w-spacing)*0.5;
	let fontSize=14;	
	
	print('printPDF: entry['+field.name);
	print('printPDF: field type:'+field.type);

	//measure text
	let label=entry[field.name];
	let opt={width:w1};
	config.doc.fontSize(fontSize);
	
	//for more eloquent display the height of the text
	//can be measured prior to output
	//use currentLineHeight to scale height
	//let lineH=config.doc.currentLineHeight(1);
	//let h=config.doc.heightOfString(label,opt)/lineH;


	//print label
	config.doc.font('Courier').text(label,opt);
	
	
}