function print(config,msg){
	let el=config.document.getElementById(config.debugId);
	if (el===null) {
		//alert("Debug section not initialized. Message: "+msg);
		return;
	}
	el.value+="\n"+msg;
}

function clear(config){
	let el=config.document.getElementById(config.debugId);
	if (el===null) {
		//alert("Debug section not initialized");
		return;
	}
	config.document.getElementById(config.debugId).value="";
}

function createRowSelector(schemaName,queryName){
	let selectRows=new Object();
	selectRows.schemaName=schemaName;
	selectRows.queryName=queryName;
	return selectRows;
}


function buildTable(config){
	//print(config,'buildTable');
	addRow(config,'ParticipantId',[config.id]);
	let selectRows=createRowSelector('lists',config.setup);
	selectRows.success=function (data){afterSetup(config,data);}
	LABKEY.Query.selectRows(selectRows);
}

function afterSetup(config,data){
	//print(config,'afterSetup ['+data.rows.length+']');
	config.setupRows=data.rows;
	let selectRows=createRowSelector('study','DataSets');
	selectRows.success=function (data){afterDatasets(config,data);}
	LABKEY.Query.selectRows(selectRows);
}

//build a local copy of enum's
function afterDatasets(config,data){
	//print(config,'afterDatasets ['+data.rows.length+']');
	config.datasets=data.rows;
	//debug mode -> jump ahead
	//afterEnumValues(config);
	let selectRows=createRowSelector('ListManager','ListManager');
	selectRows.filterArray=[LABKEY.Filter.create('Name','enum',
		LABKEY.Filter.Types.STARTS_WITH)];
	selectRows.success=function (data){afterEnums(config,data);}
	LABKEY.Query.selectRows(selectRows);
	//print(config,'enums');
}

//parse list of lists; get values
function afterEnums(config,data){
	//print(config,'afterEnums: '+data.rows.length);
	config.enums=data.rows;
	config.enumValues=new Object();
	for (row of config.enums){
		//print(config,'afterEnums: '+row.Name);
		config.enumValues[row.Name]=new Object();
	}
	for (lst in config.enumValues){
		let selectRows=createRowSelector('lists',lst);
		selectRows.success=function (data){addEnumValues(config,data);}
		LABKEY.Query.selectRows(selectRows);
	}
}

function addEnumValues(config, data){
	//find out the variable name
	//
	let varName="NONE";
	for (field of data.metaData.fields){
		if (field.name=="Key")
			continue;
		varName=field.name;
	}

	//print(config,'addEnumValues ['+data.queryName+']: '+varName);

	config.enumValues[data.queryName].map=new Object();
	for (row of data.rows)
		config.enumValues[data.queryName].map[row["Key"]]=row[varName];
	waitForEnumCompleted(config);

}

function waitForEnumCompleted(config){
	for (lst in config.enumValues){
		if (!("map" in config.enumValues[lst]))
			return;
		//print(config,'['+lst+']: '+
		//	Object.keys(config.enumValues[lst].map).length);
	}
	//print(config,"Enum completed");
	afterEnumValues(config);
	

}

function datasetName(config,id){
	for (let i=0;i<config.datasets.length;i++){
		if (config.datasets[i].DataSetId==id)
			return config.datasets[i].Name;
	}
	return "NONE";
}

function afterEnumValues(config){
	
	config.entries=new Object();
	for (let i=0;i<config.setupRows.length;i++){
		//print(config,'['+i+']: '+config.setupRows[i].dataset);
		let queryName=datasetName(config,config.setupRows[i].dataset);

		//print(config,"Adding dataset: "+queryName);
		config.entries[queryName]=new Object();
		config.setupRows[i].datasetName=queryName;
	}
	
	for (let ds in config.entries){
		//print(config,"Querying dataset: "+ds);
		let selectRows=createRowSelector('study',ds);
		selectRows.filterArray=[LABKEY.Filter.create('ParticipantId',config.id)];
		selectRows.success=function (data){afterQuery(config,data);}
		LABKEY.Query.selectRows(selectRows);
	}
	//print(config,'afterDatasets: Done');
}

function afterQuery(config,data){
	//print(config,'afterQuery ['+data.queryName+']: '+data.rows.length);
	config.entries[data.queryName].rows=data.rows;
	config.entries[data.queryName].metaData=data.metaData;
	waitForAll(config);
}

function waitForAll(config){
	//print(config,'waitForAll');
	for (let ds in config.entries){
		if (!("rows" in config.entries[ds])) 
			return;
		//print(config,ds+': '+config.entries[ds].rows.length);
	}
	//only get here if all rows are set
	//print(config,'waitForAll: Done');
	updateValues(config);
}

function getField(fields,name){
	for (field of fields){
		if (field.name==name) 
			return field;
	}
	return undefined;
}


function updateValues(config){
	//print(config,'updateValues');
	for (let row of config.setupRows){
		let ds=row.datasetName;
		let vars=row.variables.split(';');
		//print(config,'Dataset: '+row.datasetName+' Vars: '+vars);
		if (config.entries[ds].rows.length==0){
			addRow(config,ds,["no events"],config.missingStyle);
			continue;
		}
		addRow(config,ds,vars,config.headerStyle);
		let md=config.entries[ds].metaData;
		for (let dataRow of config.entries[ds].rows){
			let displayRow=new Array();
			for (let v of vars){
				//print(config,ds+'['+v+']: '+ dataRow[v]);
				//check if it is a lookup
				let field=getField(md.fields,v);
				let value=dataRow[v];
				if ("lookup" in field){
					//print(config,"Lookup: "+field.lookup.table);
					let lut=config.enumValues[field.lookup.table];
					value=lut.map[value];
				}
				displayRow.push(value);
			}
			addRow(config,'',displayRow);
		}
	}
	E
}	

function setStyle(object,style){
	if (style!=undefined)
		for (attr in style)
			object.style[attr]=style[attr];
}

function addRow(config,header,values,style){
	//let headerColor="#d0e8f8";
	let row=config.table.insertRow();
	let cell=config.document.createElement('th');
	setStyle(cell,style);
	row.appendChild(cell);
	let cellData=config.document.createTextNode(header);
	//print(config,'Adding header '+header);
	cell.appendChild(cellData);
	//new cell
	for (v of values){
		cell=row.insertCell();
		setStyle(cell,style);
		cellData=config.document.createTextNode(v);
		cell.appendChild(cellData);
	}
}