Homepage.registerBrick({
	name:"ejd_test_API",
	title:"Basic API read test",
	description:"Test getById,getAll,getByProperty,getByProperties for core and model classes.",
	adminOnly:true,
	version:1,
	height:3,
	width:1,
	url:"/api/",
	getAll:true,
	sortBy:"name",

	onSuccess:function(transport,box) {
		let brick=this;
		box.classList.add("hastable");
		box=box.querySelector('.boxbody');
		box.innerHTML="<p>Message: "+transport.responseJSON.message+"</p>";
		box.innerHTML+='<p>Suppressed in /api/index.php: '+transport.responseJSON["suppressed"].join(", ")+'</p>';
		box.innerHTML+='<p>Waiting for: <strong id="apitest_waitingFor">-</strong></p>';
		let classes=transport.responseJSON["classes"];
		let tests={'getAll':'gA','getById':'gBI','getByName':'gBN','getByProperty':'gBP','getByProperties':'gBPs'};
		let results=["Database errors","Manual test","Failures","Untested methods","Unimplemented methods","Success"];
		let tbl=document.createElement("table");
		tbl.style.marginTop="1.5em";
		tbl.classList.add("uitable");
		tbl.id="apiTestsInProgress";
		Object.keys(classes).forEach(function(classDirectory){

			classes[classDirectory].forEach(function (className){
				let tr=document.createElement("tr");
				let th=document.createElement("th");
				th.innerHTML=className;
				tr.classToTest=className;
				tr.appendChild(th);

				Object.keys(tests).forEach(function(test){
					let td=document.createElement("td");
					td.classList.add(test);
					td.dataset.classname=className;
					td.innerHTML=tests[test];
					td.classList.add("updating");
					td.classList.add("pending");
					tr.appendChild(td);
				});
				tbl.appendChild(tr);
			});
			box.appendChild(tbl);
			results.forEach(function (result){
				let tbl=document.createElement("table");
				tbl.classList.add("uitable");
				let tr=document.createElement("tr");
				let th=document.createElement("th");
				th.innerHTML=result;
				tbl.id="apitest_"+result.toLowerCase().replace(" ","_");
				tr.appendChild(th);
				tbl.appendChild(tr);
				box.appendChild(tbl);
				tbl.style.display="none";
			});
			window.setTimeout(function () {
				tbl.querySelectorAll("td").forEach(function (td) {
					brick.testGetAll(td.closest("tr"));
				});
			},100);
		});
		window.setTimeout(this.moveCompletedRowsToResults,200);
	},

	moveCompletedRowsToResults:function (){
		let rows=document.getElementById("apiTestsInProgress").querySelectorAll("tr");
		if(!rows){
			document.getElementById("apitest_waitingFor").innerHTML="0";
			return;
		}
		document.getElementById("apitest_waitingFor").innerHTML=rows.length+"";
		rows.forEach(function (tr){
			if(tr.querySelector(".pending")){
				return;
			}
			let tbl;
			if(tr.querySelector(".result_database_error")){
				tbl="apitest_database_errors";
			} else if(tr.querySelector(".result_failed")){
				tbl="apitest_failures";
			} else if(tr.querySelector(".result_manual_test")){
				tbl="apitest_manual_test";
			} else if(tr.querySelector(".result_not_tested")){
				tbl="apitest_untested_methods";
			} else if(tr.querySelector(".result_not_implemented")){
				tbl="apitest_unimplemented_methods";
			} else {
				tbl="apitest_success";
			}
			if(tbl){
				tbl=document.getElementById(tbl);
				tbl.appendChild(tr);
				tbl.style.display="table";
			}
		});
		window.setTimeout(this.moveCompletedRowsToResults, 100);
	},

	testGetAll: function(tr){
		let brick=this;
		let td=tr.querySelector(".getAll");
		td.classList.add("updating");
		let className=td.dataset.classname;
		let uri='/api/'+className;
		td.uri=uri;
		td.classList.add("done");
		td.classList.add("updating");
		td.addEventListener("click",this.openUri);
		td.style.cursor="pointer";
		new AjaxUtils.request(uri,{
			method:"get",
			onSuccess:function (xhr){
				if(xhr.responseJSON.rows && xhr.responseJSON.rows.length){
					brick.markPassed(td,uri);
					td.closest("tr").record=xhr.responseJSON.rows[0];
					window.setTimeout(brick.testGetById, 50, tr);
					window.setTimeout(brick.testGetByName, 50, tr);
					window.setTimeout(brick.testGetByProperty, 50, tr);
					window.setTimeout(brick.testGetByProperties, 50, tr);
				} else {
					return this.onFailure(xhr);
				}
			},
			onFailure:function (xhr){
				brick.handleTestFailure(xhr, td, uri);
				tr.querySelectorAll(".getById,.getByName,.getByProperty,.getByProperties").forEach(function (td){
					brick.markUntested(td,uri,'getByAll failed');
				});
			}
		});
	},

	testGetById:function(tr) {
		let td = tr.querySelector(".getById");
		let className = tr.classToTest;
		let uri='/api/'+className+'/'+tr["record"]["id"];
		if (!tr["record"]["id"]) {
			this.markUntested(td,uri, "No id property in getAll result");
			return;
		}
		this.doTest(td, uri);
	},

	testGetByName:function(tr) {
		let td = tr.querySelector(".getByName");
		let className = tr.classToTest;
		let uri='/api/'+className+'/name/'+encodeURIComponent(tr["record"]["name"]);
		if (!tr["record"]["name"]) {
			this.markUntested(td,uri, "No name property in getAll result");
			return;
		}
		this.doTest(td, uri);
	},

	propertiesForTest:[
		"projectid","owner","description","scope","loglevel","issystem","shipmentdestinationid","manufacturerdatabaseid",
		"temperature","isinuse","friendlyname","parametername","datasetid","containertypeid","containercategoryid","parent","userscancreate",
		"starrating","priority","ismanaged","iscurrent","crystalscoringsystemid","welldropid","imagerid","subs","isactive",
		"platewellid","isavailable","rawdatadoi","homepagebrickid","constructid","height","width",
		"imagingsessionid","dropimageid","crystalid","diffractionrequestid","shipmentid","plateid","fullname","usergroupid"
	],

	testGetByProperty:function(tr) {
		let td = tr.querySelector(".getByProperty");
		let className = tr.classToTest;
		let key;
		let val;
		this.propertiesForTest.forEach(function (prop){
			if(key){ return; }
			if(tr["record"][prop]){
				key=prop;
				val=encodeURIComponent(tr["record"][prop]);
			}
		});
		let uri='/api/'+className+'/'+key+"/"+val;
		if(!tr["record"][key]){
			this.markUntested(td,uri, "No suitable property in getAll result");
			return;
		}
		this.doTest(td, uri);
	},

	testGetByProperties:function(tr) {
		let td = tr.querySelector(".getByProperties");
		let className = tr.classToTest;
		let key1;
		let key2;
		let val1;
		let val2;
		this.propertiesForTest.forEach(function (prop){
			if(tr["record"][prop]){
				if(!key1){
					key1=prop;
					val1=encodeURIComponent(tr["record"][prop].replaceAll("/+/","%2B"));
				} else if(!key2){
					key2=prop;
					val2=encodeURIComponent(tr["record"][prop]).replaceAll(/[+]/g,"%2B");
				}
			}
		});
		if(!key1 || !key2){
			this.markUntested(td,'/', "Could not find two suitable properties in getAll result");
			return;
		}
		let uri='/api/'+className+'/'+key1+"/"+tr["record"][key1]+'/'+key2+"/"+tr["record"][key2];
		this.doTest(td, uri);
	},

	doTest:function (td, uri){
		if(td.classList.contains("done")){ return; }
		td.classList.add("done");
		td.classList.add("updating");
		td.uri=uri;
		let brick=this;
		td.addEventListener("click",brick.openUri);
		td.style.cursor="pointer";
		new AjaxUtils.request(uri,{
			method:"get",
			onSuccess:function (xhr){
				if(!xhr.responseJSON){
					return this.onFailure(xhr);
				}
				brick.markPassed(td, uri);
			},
			onFailure:function (xhr){
				brick.handleTestFailure(xhr, td, uri);
			}
		});
	},

	handleTestFailure:function(xhr, td, uri){
		let brick=this;
		if(!xhr.responseJSON){
			let tr=td.closest("tr");
			if(td.classList.contains("getById") && (tr.classToTest.endsWith("file") || tr.classToTest.endsWith("thumb"))) {
				brick.markManualTestNeeded(td, uri, "File download. Click to test.");
			} else {
				brick.markFailed(td, uri, xhr.status+ " (bad JSON)");
			}
		} else if(xhr.responseJSON.error){
			if(xhr.responseJSON.error.toLowerCase().indexOf('sqlstate')>=0) {
				brick.markFailedDatabaseError(td, uri, xhr.status+" ("+xhr.responseJSON.error+")");
			} else if(xhr.responseJSON.error.toLowerCase().indexOf('not implemented')>=0) {
				brick.markUnimplemented(td, uri, xhr.status+" ("+xhr.responseJSON.error+")");
			} else {
				brick.markFailed(td, uri, xhr.status+" ("+xhr.responseJSON.error+")");
			}
		}
		return false;
	},

	markPassed:function(td,uri,message){
		this.markCell(td,uri,'Passed',message,"#9f9","#060");
	},

	markFailed:function(td,uri,message){
		this.markCell(td,uri,'Failed',message,"#f99","#600");
	},

	markFailedDatabaseError:function(td,uri,message){
		this.markCell(td,uri,'Database error',message,"#f9f","#606");
	},

	markUnimplemented:function(td,uri,message){
		this.markCell(td,uri,'Not implemented',message,"#cc6","#333",true);
	},

	markUntested:function(td,uri,message){
		this.markCell(td,uri,'Not tested',message,"#ccc","#333",true);
	},

	markManualTestNeeded:function(td,uri,message){
		this.markCell(td,uri,'Manual test',message,"#99f","#006",true);
	},

	markCell:function(td,uri,title,message,bgColor,textColor,strike){
		td.uri=uri;
		td.classList.add("done");
		td.classList.remove("pending");
		td.classList.remove("updating");
		td.classList.add("result_"+title.toLowerCase().replaceAll(" ","_"));
		if(strike){ td.style.textDecoration="line-through"; }
		td.style.backgroundColor=bgColor;
		td.style.color=textColor;
		td.title=title;
		if(message){
			td.title+=": "+message;
		}
	},

	openUri:function (evt){
		let td=evt.target.closest("td");
		window.open(document.location.protocol+"//"+document.location.host+td.uri,"_blank");
	}

});