//Global variables
var DatOut,WinOut,WinCount=0;	//Simulated output data (array and window), number of windows
var cDNA, Details;	//Boolean var to create log2 ratios as output


function simchip3_input(){
//Creates a user form to enter simchip input data
var text="<p><h3>Simulation of malignant transformation<\/h3><\/p>"
+"<form name=\"f_inp3\" action=\"\">"

+"<table style=\'font-size:9pt\';  border=\'1\'; text-align: left; cellpadding=\'2\' cellspacing=\'2\'>"
+"<tr bgcolor=\'080880\' style=\'color: white\'>"
+"<td style=\'text-align: center; width: 135px;\'><b>Experiments</b></td>"
+"<td style=\'text-align: center; width: 135px;\'><b>Probes</b></td>"
+"</tr><tr><td style=\'text-align: left\'>"
+"&nbsp;&nbsp;&nbsp;&nbsp;<input name=\"nExp\" value=\'15\'type=\'text\' title=\'0-50\' size=\'3\' onblur=\'check_Exp(this.value)\'>&nbsp;&nbsp;&nbsp;&nbsp;columns"
+"</td><td style=\'text-align: left\'>"
+"&nbsp;&nbsp;&nbsp;&nbsp;<input name=\"nPrbs\" value=\'150\'type=\'text\' title=\'0-1000\' size=\'3\' onblur=\'check_Prbs(this.value)\'>&nbsp;&nbsp;&nbsp;&nbsp;rows"
+"</td></tr><tr>"
+"<td colspan=\"2\">&nbsp;<input type=\'checkbox\' value=\"cDNA\" name=\"cDNA\">&nbsp;cDNA arrays&nbsp;&nbsp;"
+"<input type=\'checkbox\' value=\"cDNA\" name=\"Stages\">&nbsp;Stages&nbsp;&nbsp;"
+"<input type=\'checkbox\' value=\"cDNA\" name=\"Details\" checked=true>&nbsp;Details</td>"
+"</tr></table>"
+"<table style=\'font-size:9pt\';  border=\'0\'; text-align: left; cellpadding=\'2\' cellspacing=\'2\'>"
+"<tr>"
+"<td style=\'width: 220px\'><input type=\'button\' value=\'GO\' onClick=\'simchip3_main()\'></td>"
+"<td style=\'width: 50px\'><input type=\'button\' value=\'HELP\' onClick=\'simchip3_help()\'></td>"
+"</tr></table></form><br>"
+"<a href=\"./downloads/poster_2006.pdf\" target=\"poster\">Preliminary publication (in German)</a><br>"
+"<a href=\"./downloads/simchip3_shortcode.html\" target=\"SimChip3\">Simplified source code example</a>";;
document.getElementById("divTxt").innerHTML=text;
}//end of run_simchip

function simchip3_help(){
var WinHelp;
WinHelp=window.open("","","width=500,height=250,left=10,top=10,resizable=yes,scrollbars=yes,menubar=no");
	WinHelp.document.writeln("<html><head><title>SimChip 3</title></head>\n<body>");
	WinHelp.document.writeln("<h3>Simulating malignant transformation</h3>"); 
	WinHelp.document.writeln("Each time you click on GO, <i>SimChip3</i> creates a formatted table with simulated gene expression data.");
	WinHelp.document.writeln("The first column shows a normal expression profile like that in <i>Sim'Chip2</i>, the others show progressive differential expression patterns like those observed in cancer.<br>");
	WinHelp.document.writeln("If you check the <i>cDNA arrays</i> box, the program will generate relative rather than absolute signals, so-called P/R ratios (patient/reference).<br>"); 
	WinHelp.document.writeln("If you check <i>Stages</i>, the columns will be rearranged into two clusters of early and advanced cancer stages.</p>"); 
	WinHelp.document.writeln("<p><b>Background:</b> Malignant transformation of gene expression is assumed to be caused by a gradual loss of control of genetic integrity. ");  
	WinHelp.document.writeln("As a consequence differential gene expression increases from cell cycle to cell cycle, while the overall distribution pattern remains constant. ");
	WinHelp.document.writeln("This gradual loss is simulated with a stochastic Brownian fractal for S and D (see <i>SimChip1</i>).");
	WinHelp.document.writeln("This algorithm generates a sequence of virtual biochip experiments with increasing malignancy from left to right.");
	WinHelp.document.writeln("\n<\/body><\/html>");
WinHelp.document.close();
}//end of simchip2_help

function simchip3_main(){
//Input: reads number of columns and rows and creates a two-dimensional array with experimental results
//Output: creates a coloured table in a new window
//Calls brown(), hexColor() and hex()

var m=parseInt(document.f_inp3.nPrbs.value);	//m = number of rows (without head line)
var n=parseInt(document.f_inp3.nExp.value);	//n = number of columns (without names and reference)
var Stages=document.f_inp3.Stages.checked;		//confuses time sequence of experiments to make patterns less obvious
cDNA=document.f_inp3.cDNA.checked;			//calculates P/R ratios
Details=document.f_inp3.Details.checked;	//Describes experiment on top of output table
var i,j,k;	//index variables
var a,b,tx,pos1,pos2,tmp;				//for explanations see below
var min, max,cal;						//smallest random number, largest observable signal, calibration factor							
min=0.01;							//corresponds to realistic mRNA half-lives of 5 to 1000 min
max=30000;							//maximal microarray signal
cal=max*min							//calibration factor						

	var co=new Array(4);		//coordinates for fractal Brownian movement
	DatOut=new Array(m);		//array with m rows of experimental output data

   //Simulation
   for(i=0;i<m;i++){
	DatOut[i]=new Array(n+1);	//each row has n+1 columns, column[0]=reference signal
	for (k=0;k<4;k++) 
		co[k]=Math.random()*(1-min)+min;		//4 random numbers between min and 1
	
	DatOut[i][0]=cal*co[0]*co[1]*co[2]/co[3];	//reference signal (min=1.1)
	if (DatOut[i][0]<1.1) DatOut[i][0]=1.1;
	a=Math.random()*Math.random()*Math.random();	//right-skewed distribution of Brownian movements
	for (j=1;j<=n;j++){		
		if (j==Math.ceil(n/2)){
			b=a}		//big movement to create 2 clusters of early and late cancer states
		else{
			b=a/10};	//small movement
		for (k=0;k<4;k++) 
			co[k]=brown(co[k],b,min,1);		//random movement between min and 1.0
		DatOut[i][j]=cal*co[0]*co[1]*co[2]/co[3];	//pathological signal (min=1.1)
		if (DatOut[i][j]<1.1) DatOut[i][j]=1.1;
	}
   }//end of simulation
	
   //Confusion: Rearranges experiments (columns) randomly by switching columns between pos1 and pos2
   if (Stages==false) {
	for(i=1;i<n;i++){	
	   pos1=Math.ceil(n*Math.random());
	   pos2=Math.ceil(n*Math.random());
	   for(j=0;j<m;j++){
		tmp=DatOut[j][pos1];
		DatOut[j][pos2]=DatOut[j][pos1];
		DatOut[j][pos1]=tmp;
	   }
   	}//end of confusion
   }

   //Creates output table
   WinCount++;	
   WinOut=window.open("",WinCount,"width=600,height=600,left=10,top=10,resizable=yes,scrollbars=yes,menubar=yes");
   WinOut.document.writeln("<html><head><title>SimChip 3<\/title><\/head>\n<body>");
   if (Details==true) {
        WinOut.document.writeln("Simulation of " + n + " experiments demonstrating differential expression of " + m + " gene expression signals in cancer samples. Experiment 0 represents a normal sample.<br>");
        WinOut.document.writeln("Blue = underexpression, red = overexpression.<br>");
        if (cDNA==true) WinOut.document.writeln("Signals are expressed as ratios (experiment \/ reference).<br>");
        if (Stages==true) WinOut.document.writeln("Malignant transformation proceeds from left to right.<br>");
   }
   WinOut.document.writeln("<table border=\'1 \'>");
   WinOut.document.write("<tr bgColor=\'#CCCCCC\'><td>SimChip<\/td><td>Exp0<\/td>");
   for(i=1;i<=n;i++) 
	WinOut.document.write("<td>Exp"+i+"<\/td>");
   for(i=0;i<m;i++)
	WinOut.document.writeln(parseTab(i));
   WinOut.document.writeln("<\/table>");//end of formatted table 
    
   WinOut.document.writeln("<\/body><\/html>");
   WinOut.document.close();
}//end of simchip3_main

function check_Exp(tx){
with (document.f_inp3.nExp) {
	value = parseInt(tx);
	if(isNaN(value)) value="15";
	if(value<0) value="0";
	if(value>50) value="50";
   }
}
function check_Prbs(tx){
with (document.f_inp3.nPrbs) {
	value = parseInt(tx);
	if(isNaN(value)) value="150";
	if(value<0) value="0";
	if(value>1000) value="1000";
   }
}

function parseTab(index){
//Converts array row into a string with tab tags, row index and colors
//Adds some noise to each value
//Creates P/R ratios if requested
var a,b,i,x,y,z;
   var ret="<tr align=\'center\'><td bgColor=\'#CCCCCC\'>Prb"+(index+1)+"<\/td>";
   for(i in DatOut[index]){	   
	x = DatOut[index][i];		//ideal values without analytical errors
	if(i>0) {
	   a=(Math.random()-0.5)*10;		//background noise -5 to +5
	   b=(Math.random()-0.5)/10;		//signal noise x+-5%
	   y=Math.round(x+a+b*x);					
	   if (y<1) y=1;}
	else {y=Math.round(x);}
	z=y/DatOut[index][0];		//ratio
	if (cDNA==true) y=Math.round(z*100)/100;	//ratio with two decimals
	ret+="<td bgColor=\'"+hexColor(z)+"\'>"+y+"<\/td>";
   }
   ret+="</td></tr>";
return ret;
}

function brown(pos,wid,min,max){
//Mandelbrot algorithm for fractal Brownian movement
//Changes the position of the reference signal randomly within a given space
//wid=width of individual Brownian movements, min and max = range limits
var ret;
	ret = pos + wid*(Math.random()-0.5);
	if (ret<min) ret=min;
	if (ret>max) ret=max;		
return ret;
}

function hexColor(ratio){
//Converts a P/R ratio into a hexadecimal RGB code 
//Ratios below 1.0 become increasingly blue, ratios above 1.0 become increasingly red
var logRatio, ret;
var R=255, G=255, B=255, f=50;
	if (ratio>16) ratio=16;
	if (ratio<1/16) ratio=1/16;
	logRatio=f*Math.log(ratio)/Math.LN2;
	G-=Math.round(Math.abs(logRatio)-0.5);	//Decreases green
	if (logRatio>0){
		B-=Math.round(logRatio-0.5);	//Decreases blue
	}
	else{
		R+=Math.round(logRatio-0.5);	//Decreases red
	}
	ret="#"+hex(R)+hex(G)+hex(B);	
return ret;        
}

function hex(dec){
//converts decimal into hexadecimal numbers
var ret = "";
var hex="0123456789ABCDEF";
	while(dec != 0) {
          ret=hex.charAt(dec%16)+ret;
          dec=dec >> 4;
	}
	if (ret=="") ret="00";
return ret;
}
