function renderMessages(id, messages) {
	if (messages && messages.length > 0) {
		let errorDiv = document.createElement('div');
		let style='padding: 10px; background-color: #ffe5e5;' 
		style+='color: #d83f48; font-weight: bold;';
		errorDiv.setAttribute('style', style);
		errorDiv.innerHTML = messages.join('<br/>');
		document.getElementById(id).appendChild(errorDiv);
	}
};

function validateChartConfig(chartConfig, aes, scales, measureStore) {
	let hasNoDataMsg = LABKEY.vis.GenericChartHelper.validateResponseHasData(measureStore, false);
	if (hasNoDataMsg != null)
		return {"success": false, "messages": [hasNoDataMsg]};

	let measureNames = Object.keys(chartConfig.measures);
	for (let i = 0; i < measureNames.length; i++) {
		let measureProps = chartConfig.measures[measureNames[i]];
		if (measureProps && 
			measureProps.name && 
			measureStore.records()[0][measureProps.name] == undefined){
					                    
			let retVal=new Object();
			retVal.success=false;
			retVal.messages=['The measure, ' + 
				measureProps.label + 
				', is not available. It may have been renamed or removed.']
			return retVal;
		}
	}

	 let messages = [];
	 let axisMeasureNames = ['x', 'xSub', 'y'];
	 for (let i = 0; i < axisMeasureNames.length; i++) {
		 if (measureNames.indexOf(axisMeasureNames[i]) > 0) {
			let validation = LABKEY.vis.GenericChartHelper.validateAxisMeasure(
				chartConfig.renderType, chartConfig, axisMeasureNames[i],
				aes, scales, measureStore.records());
			if (validation.message != null)
				messages.push(validation.message);
			if (!validation.success)
				return {"success": false, "messages": messages};
		 }
	}

	return {"success": true, "messages": messages};

}

function selectRowsCallback(renderConfig, measureStore) {
	let responseMetaData = measureStore.getResponseMetadata();
	for (let f in measureStore)
		document.getElementById('debugCode').value+='\n '+f+' '+typeof(f);
	let record=measureStore.records()[1];
	for (let f in record)
		document.getElementById('debugCode').value+='\n '+f+ ' ' +typeof(f);

	//try something stupid
	let participantField=document.getElementById('participantField').innerHTML;
	let participantCode=document.getElementById('participantCode').innerHTML;
	let visitField=document.getElementById('visitField').innerHTML;
	let visitCode=document.getElementById('visitCode').innerHTML;
	let selectedParticipantData=new Array();
	let otherParticipantData=new Array();
	let i=0;
	let maxValue=-1e30;
	while (i<measureStore.records().length){
		let record=measureStore.records()[i];
		//document.getElementById('debugCode').value+='\n '+record[participantField].value;
		let pMatch=record[participantField].value==participantCode;
		let vMatch=true;
		if (visitField in record)
			vMatch=record[visitField].value==visitCode;
		let sMatch=true;
		if ('SequenceNum' in record)
			sMatch=record['SequenceNum'].value<renderConfig.visitThreshold;

		if (pMatch && vMatch) {
			if (sMatch)
				selectedParticipantData.push(record);
			measureStore.records().splice(i,1);	
			if (!sMatch)
				continue;
			if (record['value'].value>maxValue)
				maxValue=record['value'].value;
			continue;
		}
		record[participantField].value=renderConfig.labelOthers;
		if (!pMatch || sMatch) otherParticipantData.push(record);
		measureStore.records().splice(i,1);	

	}
	document.getElementById('debugCode').value+='\nrecords: '+otherParticipantData.length;
	document.getElementById('debugCode').value+='\nownData: '+selectedParticipantData.length;
	document.getElementById('debugCode').value+='\nmaxValue: '+maxValue;
	for (let i=0;i<otherParticipantData.length;i++)
		measureStore.records().push(otherParticipantData[i]);
	for (let i=0;i<selectedParticipantData.length;i++)
		measureStore.records().push(selectedParticipantData[i]);
	

        // chartConfig is the saved information about the chart (labels, scales, etc.)

	let chartConfig = new Object();
	chartConfig.renderType="line_plot";


	let mX=new Object();
	mX.displayFieldJsonType="";
        mX.hidden=false;
        mX.fieldKey="percentile";
        mX.label="Percentile";
        mX.schemaName="study";
        mX.type="float";
        mX.normalizedType="float";
        mX.measure=true;
        mX.name="percentile";
        mX.queryName="SUVQuantiles";
        mX.alias="percentile";
        mX.shortCaption="Percentile";
        mX.dimension=false;

	document.getElementById('debugCode').value+='\nplot: '+renderConfig.plot;
	if (renderConfig.plot=="time"){
		mX.fieldKey="SequenceNum";
		mX.label="Visit ID";
		mX.name="SequenceNum";
		mX.alias="Visit";
		mX.shortCaption="Visit ID";
	}

	let mY=new Object();
        mY.displayFieldJsonType="";
        mY.hidden=false;
        mY.fieldKey="value";
        mY.label="SUV Value";
        mY.schemaName="study";
        mY.type="float";
        mY.normalizedType="float";
        mY.measure=true;
        mY.name="value";
        mY.queryName="SUVQuantiles";
        mY.alias="value";
        mY.shortCaption="Value";
        mY.dimension=false;


	let mS=new Object();
        mS.displayFieldJsonType="";
        mS.hidden=false;
        mS.fieldKey=participantField;
        mS.label="Participant ID";
        mS.schemaName="study";
        mS.type="string";
        mS.normalizedType="string";
        mS.measure=false;
        mS.name=participantField;
        mS.queryName="SUVQuantiles";
        mS.alias=participantField;
        mS.shortCaption="Participant ID";
        mS.dimension=true;

	chartConfig.measures=new Object();
        chartConfig.measures.x=mX;
        chartConfig.measures.y=mY;
        chartConfig.measures.series=mS;
        chartConfig.measures.pointClickFn=null;
        chartConfig.scales=new Object();
        chartConfig.scales.x=new Object();
        chartConfig.scales.x.trans="linear";
        chartConfig.scales.y=new Object();
        chartConfig.scales.y.trans="linear";
	chartConfig.scales.y.min=0;
	chartConfig.scales.y.max=renderConfig.max;
	if (renderConfig.max<0)
		chartConfig.scales.y.max=1.5*maxValue;
        chartConfig.labels=new Object();
        chartConfig.labels.main=renderConfig.title;
        chartConfig.labels.subtitle="";
        chartConfig.labels.x="Percentile";
        chartConfig.labels.y="SUV Value";
 	chartConfig.width=null;
        chartConfig.height=null;
        chartConfig.pointType="outliers";
        chartConfig.geomOptions=new Object();
        chartConfig.geomOptions.label="SUVQuantiles";
        chartConfig.geomOptions.subtitle="";
        chartConfig.geomOptions.width=null;
        chartConfig.geomOptions.height=null;
        chartConfig.geomOptions.pointType="outliers";
        chartConfig.geomOptions.pointFillColor="111111";
        chartConfig.geomOptions.lineWidth=2;
        chartConfig.pointFillColor="111111";
        chartConfig.lineWidth="3";
        chartConfig.lineColor="000000";
        chartConfig.boxFillColor="3366FF";
        chartConfig.hideDataPoints=false;
//        chartConfig.colorPaletteScale="ColorDiscrete";
        chartConfig.geomOptions.colorPaletteScale="Light";
        chartConfig.chartLayout="single";
        chartConfig.chartSubjectSelection="subjects";
        chartConfig.displayIndividual=true;
        chartConfig.displayAggregate=false;
        chartConfig.errorBars="None";
        chartConfig.pieInnerRadius=0;
	chartConfig.pieOuterRadius=80;
        chartConfig.showPiePercentages=true;
        chartConfig.pieHideWhenLessThanPercentage=5;
        chartConfig.piePercentagesColor="333333";
        chartConfig.gradientPercentage=95;
        chartConfig.gradientColor="FFFFFF";
        chartConfig.binThreshold=10000;
        chartConfig.binShapeGroup="hex";
        chartConfig.binColorGroup="BlueWhite";
        chartConfig.binSingleColor="000000";
        chartConfig.showOutliers=true;
        chartConfig.binShape="hex";

        chartConfig.labels.x="Percentile";


	if (renderConfig.plot=="time"){
        	chartConfig.labels.x="Visit ID";
        	chartConfig.labels.y="SUV"+renderConfig.suv+"%";
	}

	if (!chartConfig.hasOwnProperty('width') || 

		chartConfig.width == null) 
		chartConfig.width = 1000;
        if (!chartConfig.hasOwnProperty('height') || 
		chartConfig.height == null) 
		chartConfig.height = 600;
	if (renderConfig.hasOwnProperty('width')){
		chartConfig.width=renderConfig.width;
		chartConfig.height=0.6*renderConfig.width;
	}


	let xAxisType = chartConfig.measures.x ? (
		chartConfig.measures.x.normalizedType || 
		chartConfig.measures.x.type) : null;
        let chartType = LABKEY.vis.GenericChartHelper.getChartType(
		chartConfig.renderType, xAxisType);
        let aes = LABKEY.vis.GenericChartHelper.generateAes(
                chartType, chartConfig.measures, 
		responseMetaData.schemaName, responseMetaData.queryName);

        let valueConversionResponse = 
		LABKEY.vis.GenericChartHelper.doValueConversion(
			chartConfig, aes, chartType, measureStore.records());
     	if (!Ext4.Object.isEmpty(valueConversionResponse.processed)) {
               Ext4.Object.merge(chartConfig.measures, 
		       valueConversionResponse.processed);
               aes = LABKEY.vis.GenericChartHelper.generateAes(
                       chartType, chartConfig.measures, 
		       responseMetaData.schemaName, responseMetaData.queryName);
        }
        let data = measureStore.records();
	
        if (chartType == 'scatter_plot' && 
		data.length > chartConfig.geomOptions.binThreshold) {
               chartConfig.geomOptions.binned = true;
        }
        let scales = LABKEY.vis.GenericChartHelper.generateScales(
		chartType, chartConfig.measures, chartConfig.scales, 
		aes, measureStore);
        let geom = LABKEY.vis.GenericChartHelper.generateGeom(
		chartType, chartConfig.geomOptions);
	document.getElementById('debugCode').value+='\n geom color '+geom.color;
	

        let labels = LABKEY.vis.GenericChartHelper.generateLabels(
		chartConfig.labels);

	if (chartType == 'bar_chart' || chartType == 'pie_chart') {
            	let dimName = null, subDimName = null; measureName = null,
	               aggType = 'COUNT';

        	if (chartConfig.measures.x) {
			dimName = chartConfig.measures.x.converted ? 
				chartConfig.measures.x.convertedName : 
				chartConfig.measures.x.name;
        	}
        	if (chartConfig.measures.xSub) {
	        	subDimName = chartConfig.measures.xSub.converted ? 
				chartConfig.measures.xSub.convertedName : 
				chartConfig.measures.xSub.name;
		}
	
		if (chartConfig.measures.y) {
			measureName = chartConfig.measures.y.converted ? 
				chartConfig.measures.y.convertedName : 
				chartConfig.measures.y.name;

			if (Ext4.isDefined(chartConfig.measures.y.aggregate)) {
				aggType = chartConfig.measures.y.aggregate;
                	}
                	else if (measureName != null) {
				aggType = 'SUM';
			}

		}


		data = LABKEY.vis.getAggregateData(data, dimName, subDimName, 
			measureName, aggType, '[Blank]', false);
        }

	let plotConfig = LABKEY.vis.GenericChartHelper.generatePlotConfig(
		renderConfig.chartId,chartConfig, labels, aes, scales, geom, data);
	document.getElementById('debugCode').value+='\n plotConfig layers: '+plotConfig.layers.length;
	for (let i=0;i<plotConfig.layers.length;i++){
		let l=plotConfig.layers[i];
		document.getElementById('debugCode').value+='\n color: '+l.aes.pathColor;
		if (l.data===null)
			continue;
		document.getElementById('debugCode').value+='\n data: '+l.data.length;

	}
        let validation = validateChartConfig(chartConfig, aes, scales, measureStore);
        renderMessages(renderConfig.chartId, validation.messages);
        if (!validation.success)
            return;
	
	let plot;
        if (chartType == 'pie_chart') {
            new LABKEY.vis.PieChart(plotConfig);
        }
        else {
            plot = new LABKEY.vis.Plot(plotConfig);
            plot.render();
        }
	   



}

function plotAll() {

	let participantField=document.getElementById('participantField').innerHTML;
	let visitField=document.getElementById('visitField').innerHTML;
	document.getElementById('debugCode').value+='\n'+participantField;

	let organs=["3","4","5"];
		
	for (let i=0;i < organs.length; i++){

		let renderConfig=new Object();
        	//all additional configuration stuff goes in here

		renderConfig.chartId='SUVall_organ'+organs[i];
		renderConfig.width=500;
		renderConfig.participantCode=document.getElementById("participantCode").innerHTML;
		renderConfig.visitCode=document.getElementById("visitCode").innerHTML;
		renderConfig.labelOthers='other visits/participants';
		renderConfig.plot="percentile";
		renderConfig.max=10;
		renderConfig.title="SUV cumulative distribution";

		// When all the dependencies are loaded we then load the data via the MeasureStore selectRows API.
		// The queryConfig object stores all the information needed to make a selectRows request
		
		let queryConfig = new Object;
	        queryConfig.schemaName="study";
        	queryConfig.queryName="SUVQuantiles";
        	queryConfig.viewName=null;
        	queryConfig.dataRegionName="Dataset";
	        queryConfig.queryLabel="SUVQuantiles";
        	queryConfig.parameters= new Object();
		queryConfig.requiredVersion=13.2;
	        queryConfig.maxRows=-1;
        	queryConfig.sort="lsid";
	        queryConfig.method="POST";
        	queryConfig.columns=["percentile","value",participantField,visitField];
	        queryConfig.filterArray=new Array();
        	//queryConfig.filterArray.push({
		//	"name":"patientCode",
		//	"value":renderConfig.participantCode,
		//	"type":"eq"});
	        //queryConfig.filterArray.push({
		//	"name":"visitCode",
		//	"value":renderConfig.visitCode,
		//	"type":"eq"});
        	queryConfig.filterArray.push({
			"name":"organ",
			"value":organs[i],
			"type":"eq"});

		if (queryConfig.filterArray && 
			queryConfig.filterArray.length > 0) {
            		let filters = [];
            		for (let i = 0; i < queryConfig.filterArray.length; i++) {
                		let f = queryConfig.filterArray[i];
                		filters.push(LABKEY.Filter.create(
					f.name,  f.value, 
					LABKEY.Filter.getFilterTypeForURLSuffix(f.type)));
            		}
            		queryConfig.filterArray = filters;
        	}
        	queryConfig.success = function(data){
			selectRowsCallback(renderConfig,data);};
        	queryConfig.containerPath = LABKEY.ActionURL.getContainer();
        	LABKEY.Query.MeasureStore.selectRows(queryConfig);
	}
};

function plotParticipant() {

	let participantField=document.getElementById('participantField').innerHTML;
	let participantCode=document.getElementById('participantCode').innerHTML;
	let visitField=document.getElementById('visitField').innerHTML;
	let visitCode=document.getElementById('visitCode').innerHTML;

	let visitValue=parseInt(visitCode.split('_')[1])+1;
	document.getElementById('debugCode').value+='\n'+visitValue;

	let organs=["3","4","5"];
		
	for (let i=0;i < organs.length; i++){

		let renderConfig=new Object();
        	//all additional configuration stuff goes in here

		renderConfig.chartId='SUVparticipant_organ'+organs[i];
		renderConfig.width=500;
		renderConfig.participantCode=document.getElementById("participantCode").innerHTML;
		renderConfig.visitCode=document.getElementById("visitCode").innerHTML;
		renderConfig.labelOthers='other visits';
		renderConfig.plot="percentile";
		renderConfig.max=10;
		renderConfig.title="SUV cumulative distribution";
		renderConfig.visitThreshold=visitValue;

		// When all the dependencies are loaded we then load the data via the MeasureStore selectRows API.
		// The queryConfig object stores all the information needed to make a selectRows request
		
		let queryConfig = new Object;
	        queryConfig.schemaName="study";
        	queryConfig.queryName="SUVQuantiles";
        	queryConfig.viewName=null;
        	queryConfig.dataRegionName="Dataset";
	        queryConfig.queryLabel="SUVQuantiles";
        	queryConfig.parameters= new Object();
		queryConfig.requiredVersion=13.2;
	        queryConfig.maxRows=-1;
        	queryConfig.sort="lsid";
	        queryConfig.method="POST";
        	queryConfig.columns=["SequenceNum","percentile","value",participantField,visitField];
	        queryConfig.filterArray=new Array();
        	queryConfig.filterArray.push({
			"name":"patientCode",
			"value":renderConfig.participantCode,
			"type":"eq"});
	        //queryConfig.filterArray.push({
		//	"name":"visitCode",
		//	"value":renderConfig.visitCode,
		//	"type":"eq"});
        	queryConfig.filterArray.push({
			"name":"organ",
			"value":organs[i],
			"type":"eq"});

		if (queryConfig.filterArray && 
			queryConfig.filterArray.length > 0) {
            		let filters = [];
            		for (let i = 0; i < queryConfig.filterArray.length; i++) {
                		let f = queryConfig.filterArray[i];
                		filters.push(LABKEY.Filter.create(
					f.name,  f.value, 
					LABKEY.Filter.getFilterTypeForURLSuffix(f.type)));
            		}
            		queryConfig.filterArray = filters;
        	}
        	queryConfig.success = function(data){
			selectRowsCallback(renderConfig,data);};
		queryConfig.containerPath=LABKEY.ActionURL.getContainer();
        	LABKEY.Query.MeasureStore.selectRows(queryConfig);
	}
};

function plotTime() {

	let participantField=document.getElementById('participantField').innerHTML;
	let participantCode=document.getElementById('participantCode').innerHTML;
	let visitField=document.getElementById('visitField').innerHTML;
	let visitCode=document.getElementById('visitCode').innerHTML;

	let visitValue=parseInt(visitCode.split('_')[1])+1;
	document.getElementById('debugCode').value+='\n'+visitValue;



	let organs=["3","4","5"];
		
	for (let i=0;i < organs.length; i++){

		let renderConfig=new Object();
        	//all additional configuration stuff goes in here

		renderConfig.chartId='SUVparticipant_organ'+organs[i];
		renderConfig.width=500;
		renderConfig.participantCode=document.getElementById("participantCode").innerHTML;
		renderConfig.visitCode=document.getElementById("visitCode").innerHTML;
		renderConfig.labelOthers='others';
		renderConfig.suv=95;
		renderConfig.plot="time";
		if (organs[i]=="4")
			renderConfig.suv=70;
		renderConfig.max=-1;
		renderConfig.visitThreshold=visitValue;
		renderConfig.title="Quantitative inflamation time-curve";

		// When all the dependencies are loaded we then load the data via the MeasureStore selectRows API.
		// The queryConfig object stores all the information needed to make a selectRows request
		
		let queryConfig = new Object;
	        queryConfig.schemaName="study";
        	queryConfig.queryName="SUVQuantiles";
        	queryConfig.viewName=null;
        	queryConfig.dataRegionName="Dataset";
	        queryConfig.queryLabel="SUVQuantiles";
        	queryConfig.parameters= new Object();
		queryConfig.requiredVersion=13.2;
	        queryConfig.maxRows=-1;
        	queryConfig.sort="lsid";
	        queryConfig.method="POST";
        	queryConfig.columns=["SequenceNum","value",participantField];
	        queryConfig.filterArray=new Array();
        	//queryConfig.filterArray.push({
		//	"name":"patientCode",
		//	"value":renderConfig.participantCode,
		//	"type":"eq"});
	        queryConfig.filterArray.push({
			"name":"percentile",
			"value":renderConfig.suv,
			"type":"eq"});
        	queryConfig.filterArray.push({
			"name":"organ",
			"value":organs[i],
			"type":"eq"});

		if (queryConfig.filterArray && 
			queryConfig.filterArray.length > 0) {
            		let filters = [];
            		for (let i = 0; i < queryConfig.filterArray.length; i++) {
                		let f = queryConfig.filterArray[i];
                		filters.push(LABKEY.Filter.create(
					f.name,  f.value, 
					LABKEY.Filter.getFilterTypeForURLSuffix(f.type)));
            		}
            		queryConfig.filterArray = filters;
        	}
        	queryConfig.success = function(data){
			selectRowsCallback(renderConfig,data);};
        	queryConfig.containerPath = LABKEY.ActionURL.getContainer();
        	LABKEY.Query.MeasureStore.selectRows(queryConfig);
	}
};