var mozilla=false;
var textsel=0;
// Simulation of cuff and artery dynamics
var simulating=false;
var stopflag=false;
var dtimer=50;
var tickerId;

// Canvases (use smaller canvases for performance):
var dg0;
var dg1;
var dg2;
var dg3;
var dg4;
var dg5;
var dg6;
var jg;
var wg;
var hg;
var bgr;

var lgray="#c0c0c0";
var lwhite="#FFFFFF";
var lred="#FF4000";
var lrose="#FF8080";
var lyellow="#FFFF00";
var lorange="#FFA000";
var lgreen="#00FF00";
var lblue="#00A0FF";
var lgreen="#00FF40";
// Y-value arrays
var yp8;
var yc8;
var yv8; 
//Scalings:
var ky=2.0;
var vay=1;
var vby=1.3;
// Graph windows:
var x1=39;
var y1=0;
var dx=450;
var dy=360;
var y0=294;
var x=0;
var xold=0;
var xstop=300;

var abparray=new Array(84.2, 84.0, 83.8, 83.6, 83.4, 83.2, 83.0, 82.8, 82.6, 82.4, 82.2, 82.0, 81.8, 81.6, 81.5, 81.3, 81.1, 80.9, 80.7, 80.6, 80.4, 80.2, 80.0, 79.8, 79.7, 79.5, 79.3, 79.1, 78.9, 78.7, 78.5, 78.4, 78.2, 78.0, 77.8, 77.6, 77.4, 77.2, 76.9, 76.7, 76.5, 76.3, 76.1, 75.9, 75.7, 75.6, 75.5, 75.5, 75.7, 76.2, 76.9, 77.9, 79.2, 80.8, 82.7, 84.9, 87.2, 89.8, 92.4, 95.0, 97.7, 100.3, 102.7, 105.1, 107.3, 109.3, 111.1, 112.8, 114.2, 115.5, 116.6, 117.5, 118.2, 118.7, 119.1, 119.3, 119.4, 119.4, 119.2, 119.0, 118.7, 118.3, 117.8, 117.3, 116.8, 116.2, 115.6, 115.1, 114.5, 114.0, 113.6, 113.1, 112.7, 112.3, 112.0, 111.7, 111.5, 111.3, 111.1, 111.0, 110.8, 110.7, 110.6, 110.4, 110.3, 110.1, 109.9, 109.7, 109.4, 109.0, 108.7, 108.2, 107.7, 107.2, 106.6, 106.2, 105.8, 105.5, 105.3, 105.2, 105.1, 105.0, 105.0, 105.1, 105.1, 105.1, 105.2, 105.3, 105.3, 105.4, 105.4, 105.4, 105.4, 105.4, 105.4, 105.3, 105.3, 105.2, 105.0, 104.9, 104.7, 104.5, 104.2, 103.9, 103.6, 103.3, 103.0, 102.6, 102.2, 101.8, 101.4, 100.9, 100.5, 100.0, 99.6, 99.1, 98.7, 98.2, 97.8, 97.3, 96.9, 96.5, 96.1, 95.7, 95.3, 94.9, 94.5, 94.2, 93.8, 93.5, 93.2, 92.9, 92.6, 92.3, 92.0, 91.8, 91.5, 91.2, 91.0, 90.7, 90.5, 90.2, 90.0, 89.8, 89.5, 89.3, 89.1, 88.8, 88.6, 88.3, 88.1, 87.9, 87.6, 87.4, 87.2, 86.9, 86.7, 86.5, 86.2, 86.0, 85.8, 85.6, 85.3, 85.1, 84.9, 84.7,-100,-100);  // Blood pressure driving force

var simt=0;
var i=0;
var swidth=1;

var cuffinflate=false;
var conventional=true;
var servoactive=false;
var servomode=false;
var servocount=0;
var cuffcount=0;
var startup=10;
//var Ki=0.018;
//var Kp=0.3;
var dPref=-0.015;	// Deflation rate of cuff in conventional mode
var Pcuff=0;
var Pcuff0=0;
var Pref=0;
var Psys=0;
var Pservo=0;
var PIservo=0;
var Tservo=0.075;
var Tcuff=0.008;
var Ki=0.02;
var Kp=0.5;



// Artery model parameters and variables:
var Pax=84.2;
var Paxw=84.2;
var Vax=0;
var Lax=0.1;
var Cax=0.10;
var Dax=0.5;
var Pa=84.2;    	// proximal under cuff pressure
var Pb=84.2;		// distal under cuff pressure
var Paw=84.2;		// arm windkessel pressure
var Pu=84.2;		// u is for under arm
var Gp=0.125;		// Peripheral resistance (regulated)
var Tp=0.0015;	// Time constant for autoreg
var Vset=20;		// Flow setpoint (autoreg)
var Vref=6;		// Flow reference for servo
var dVerr=0;		// Doppler noise error
var Verr=0;
var Cu=0.03;
var Du=0.30;
var Lu=0.3;
var Vu=0;
var Gc=30;
var Cb=0.01;
var Ca=0.007;
var La=0.5;
var Da=0.20;
var Va=0;
var Va0=0;
var Vc=0;
var Pd=0;
var Pbw=84;
var pimage=0;		// Image no for cuff pressurization
var aimage=0;		// Image no for artery dynamics
var dimage=0;		// Image on distal part of brachial artery
var bimage=0;		// Image of bulb
var vimage=0;

function puffyinit() {	
	Tcuff=0.075;
	textsel=0;
	conventional=false;
	servomode=true;
	servoactive=false;
}

function startTimer()
{
	tickerId=setTimeout('timerTick()',dtimer);
}

function endTimer()
{
//	if (tickerId) {
		clearTimeout(tickerId);
//		tickerId=0;
//	}
}

function simmanual()
{
	var k=0;
	simulating=true;
	for (k=0;k<8;k++){ 
		stepsim(); 
		drawsim(); 
	}
	simulating=false;
}

function timerTick()
{
	endTimer();
	if (simulating){
		stepsim();
		drawsim();
		startTimer();
	}
}

function textline(size,color,cmdtext)
{
	if (mozilla) return;
 	hg.clear();
	hg.setFont('verdana', size , Font.BOLD);
	hg.setColor(color);
	hg.drawString(cmdtext,2, 0);
  	hg.paint();
	if (conventional) startup=0;
}

function textout()
{
	if (servomode){
		if ( textsel == 0 ) { textline('12px',lrose,'Get instrument component description by placing cursor over item' ); return; }
		if ( textsel == 1 ) { textline('14px',lorange,'Click on <i>Inflate Cuff</i> to start the recording sequence' ); return; }
		if ( textsel == 2 ) { textline('14px',lyellow,'Click on <i>Start Servo Op.</i> to continue the recording sequence' ); return; }
		if ( textsel == 3 ) { textline('14px',lblue,'The cuff should now be tracking ABP in real time!' ); return; }
	} else {
		if ( textsel == 0 ) { textline('14px',lblue,'Click on Bulb to Inflate Cuff' ); return; }
 		if ( textsel == 1 ) { textline('14px',lorange, 'Continue pumping until above systolic BP' ); return; }
		if ( textsel == 2) { textline('14px',lyellow, 'You may stop pumping, cuff will be slowly deflated' ); return; }
		if ( textsel == 3) { textline('16px',lrose, 'Flow detected: Systolic BP of '+Math.round(Psys)+' mmHg' );}
	}
}

function heading(x,headingtext)
{
	if (mozilla) return;
	jg.clear();
	jg.setFont('verdana', 16 , Font.Bold); 
	jg.setColor("#F0F0D0");
	jg.drawString(headingtext,-32+x,-21);
	jg.paint();
}

function initsim()
{
	yp8= new Array(0,0,0,0,0,0,0,0,0);
	yc8= new Array(0,0,0,0,0,0,0,0,0);
	yv8= new Array(0,0,0,0,0,0,0,0,0);
	yp8[0]=y0-abparray[0]*ky;
	yv8[0]=y0;
	yc8[0]=y0;
	clearsim(dg0);
}

function clearsim(g){ 
	g.clear();
	g.setColor("#c0c0c0"); 		// gray
	g.drawLine(0,y0,64,y0);
	g.paint(); 
}

function simtinc(dt)
{
	if (dtimer<30) dt=dt/2;
	if (dtimer>=100) dt=dt+dt;
	dtimer=dtimer+dt;
	if (dtimer<5){ dtimer=5;}
	textline( '14px',lgray,'Delay:'+dtimer*0.125+' msec'); 
//	if (dt>0) { abpmain.style.visibility='visible';  } else { abpmain.style.visibility='hidden';  }

}

function startsim(){
	clearsim(dg0);
	simulating=true;
	stopflag=false;
	startTimer();
	x=0;
	textline( '14px',lyellow,'Simulation Started'); 
	startup=16;
}

function stopsim()
{
	stopflag=true;
	if (stopflag) { textline( '14px',lyellow,'Simulation will be halted'); }
}

function simtoggle()
{
	if ((simulating)&&(!stopflag)) { stopsim();} else { startsim(); }
}

function graphinit(){
	
	dg0 = new jsGraphics("dC0");
	if (!mozilla){
		dg1 = new jsGraphics("dC1");
		dg2 = new jsGraphics("dC2");
		dg3 = new jsGraphics("dC3");
		dg4 = new jsGraphics("dC4");
		dg5 = new jsGraphics("dC5");
		dg6 = new jsGraphics("dC6");
	}
	jg = new jsGraphics("aCanvas");
	wg = new jsGraphics("wCanvas");
	if (!mozilla){
		bgr = new jsGraphics("bCanvas");
		hg = new jsGraphics("hCanvas");
	}
}

function drawsim()
{
// Draw out results:
	var g;
	var lx=x;
	g=dg0;

	if (!mozilla){
		if (x>=64) { lx=lx-64; g=dg1; }
		if (lx>=64) { lx=lx-64; g=dg2; }
		if (lx>=64) { lx=lx-64; g=dg3; }
		if (lx>=64) { lx=lx-64; g=dg4; }
		if (lx>=64) { lx=lx-64; g=dg5; }
		if (lx>=64) { lx=lx-64; g=dg6; }
	}
	var i=0;
	if (!simulating) return;
	if (lx<4) {
		clearsim(g);
		if (conventional) mmHgdraw();
		if (startup>0){
			startup--;
			if (startup==0) { 
				if (servomode){
					if (textsel==0){
						startup=10;
						textout(); 
						textsel=1;
					} else { 
						textsel=1; 
						textout();
					}
				} else { textsel=0; textout();}
			}
		}
	}
	xold=lx;
	g.setStroke(swidth);
	g.setColor("#FF0000");		// red for ABP
	while (i<8) { g.drawLine(lx,yp8[i],lx,yp8[i+1]); ++i; ++lx; }
	i=0;
	lx=xold;
	g.setColor("#00FF00");		// green for Doppler
	while (i<8) { g.drawLine(lx,yv8[i],lx,yv8[i+1]); ++i; ++lx; }
//	if (!mozilla){
	i=0;
	lx=xold;
	g.setColor("#80A0FF");	// blue for cuff
	while (i<8) { g.drawLine(lx,yc8[i],lx,yc8[i+1]); ++i; ++lx; }
//	}
	yv8[0]=yv8[8];
	yp8[0]=yp8[8];
	yc8[0]=yc8[8];
	g.paint();
	x=x+8;
}

function mmHgdraw()
{
	if (((Pcuff-Pcuff0)>=1)||((Pcuff0-Pcuff)>=1)){
		var y0=218;
		bgr.clear();
		bgr.setColor(lgray);
		bgr.drawLine(0,y0,0,y0-Pcuff);
		bgr.drawLine(2,y0,2,y0-Pcuff);
		bgr.setColor(lwhite);
		bgr.drawLine(1,y0,1,y0-Pcuff-1);
		Pcuff0=Pcuff;
		bgr.paint();
	}
}

function drawaxis() // Draws the axis for the waveform display window
{
	var j;
	var dy1;
	var dx1;
	var y;

	wg.clear();
	wg.setColor("#c0c0c0");					// gray
	wg.drawRect(x1,y1,dx,dy);				// Frame

	dy1=-10*ky;
	y=y0+1-dy1-dy1-dy1;
	j=-3;
	wg.setFont("verdana", "11px", Font.BOLD);
	while (y>0){							// Draw tics with scaling
		wg.drawLine(x1-4,y,x1,y);
		if ((j%2)==0) {
			dx1=14;
			if (j>1) dx1=21;
			if ((j>9)||(j<-1)) dx1=28;
			wg.drawString(j*10,x1-dx1,y-7);
		}
		++j;
		y=y0+1+j*dy1;
	}
	wg.paint();
	clearsim(dg0);
	if (!mozilla){
		clearsim(dg1);
		clearsim(dg2);
		clearsim(dg3);
		clearsim(dg4);
		clearsim(dg5);
		clearsim(dg6);
	}
}

function togglecuff()
{
	cuffinflate=!cuffinflate;
	var id="inflate";
	if (!cuffinflate) { Pref=0; }
}

function cuffdeflate()
{
	cuffinflate=false;
	Pref=0;
}

function bulbdraw( n )
{
	if (mozilla) return;
	if (bimage==n) return;
	if (bimage==0) bu0.style.visibility='hidden';
	if (bimage==1) bu1.style.visibility='hidden';
	if (bimage==2) bu2.style.visibility='hidden';
	if (bimage==3) bu3.style.visibility='hidden';
	bimage=n;
	if (bimage==0) bu0.style.visibility='visible';
	if (bimage==1) bu1.style.visibility='visible';
	if (bimage==2) bu2.style.visibility='visible';
	if (bimage==3) bu3.style.visibility='visible';
}

function pressbulb()
{
	if (textsel != 2) {
		textsel=1;
		textout();
	}
	cuffinflate=true;
	servomode=false;
	servoactive=false;
	conventional=true;
	Pref=Pref+15;
	if (Pref>200) Pref=200;
	Tcuff=0.030;
	cuffcount=50;
	bulbdraw(1);
}

function conventionalcuff()
{
	servomode=false;
	servoactive=false;
	conventional=true;
	togglecuff();
}

function hideElement(element_id) 
{
   if (document.getElementById &&
         document.getElementById(element_id) &&
         document.getElementById(element_id).style)
      document.getElementById(element_id).style.visibility="hidden";
}

function showElement(element_id) 
{
   if (document.getElementById &&
         document.getElementById(element_id) &&
         document.getElementById(element_id).style)
      document.getElementById(element_id).style.visibility="visible";
}


function servocuff(mode)
{
	if (((mode==1)&&(cuffinflate))||((mode==0)&&(!cuffinflate))) return;
	startup=0;
	if (mode==2){
		if (!cuffinflate){	 textline('13px',lorange,'The cuff must be inflated before using servo' ); return;	}
		PIservo=Pcuff;
		Pservo=Pcuff;
		servoactive=true;
		textsel=3;
		textout();
		return;
	}
	Pref=140;
	togglecuff();
	if (cuffinflate){	
		servocount=100; 
		textsel=2;
		textout();
		hideElement('valve5');
	} else {
		servocount=0;
		textsel=1;
		textout();
		servoactive=false;
		showElement('valve5');
	}
	conventional=false;
}

function arteryocclude( dp ) {
//	if (mozilla) return;
	var ai=0;
	var di=0;
	var ddp=Pcuff-Pb-5;
	if (dp<0){
		ai=6; 
		if ( dp<-5 ) ai=7;
		if (dp<-12) ai=8;
		if (dp<-25) ai=9;
		if (ddp>0) {
			di=9;
			if (ai<7) di=6;
		}
	} else {
		if (dp<=5) { ai=5; if (ddp>0) di=5; }
		if (dp>5) { ai=4; if (ddp>0) di=4; }
		if (dp>10) { ai=3; }
		if (dp>20) { ai=2; }
		if (dp>30) { ai=1; }
		if (dp>50) { ai=0; }
	}
	if ((di!=dimage)&&(dimage>0)) {
		if (dimage==9) bd9.style.visibility='hidden';
		if (dimage==6) bd6.style.visibility='hidden';
		if (dimage==5) bd5.style.visibility='hidden';
		if (dimage==4) bd4.style.visibility='hidden';
		dimage=0;
	}

	if (ai != aimage){
		if (aimage==1) { ba1.style.visibility='hidden'; }
		if (aimage==2) { ba2.style.visibility='hidden'; }
		if (aimage==3) { ba3.style.visibility='hidden'; }
		if (aimage==4) { ba4.style.visibility='hidden'; }
		if (aimage==5) { ba5.style.visibility='hidden'; }
		if (aimage==6) { ba6.style.visibility='hidden'; }
		if (aimage==7) { ba7.style.visibility='hidden'; }
		if (aimage==8) { ba8.style.visibility='hidden'; }
		if (aimage==9) { ba9.style.visibility='hidden'; }
		aimage=ai;
		if (ai==1)  {  ba1.style.visibility='visible'; }
		if (ai==2)  { ba2.style.visibility='visible';  }
		if (ai==3)  { ba3.style.visibility='visible';  }
		if (ai==4)  { ba4.style.visibility='visible';  }
		if (ai==5)  { ba5.style.visibility='visible';  }
		if (ai==6)  { ba6.style.visibility='visible';  }
		if (ai==7)  { ba7.style.visibility='visible';  }
		if (ai==8)  { ba8.style.visibility='visible';  }
		if (ai==9)  { ba9.style.visibility='visible';  }
	}
	if (di!=dimage){
		dimage=di;
		if (di==4)  { bd4.style.visibility='visible';  }
		if (di==5)  { bd5.style.visibility='visible';  }
		if (di==6)  { bd6.style.visibility='visible';  }
		if (di==9)  { bd9.style.visibility='visible';  }
	}
}

function cuffinflation()
{
	if (mozilla) return;
	var pa=0;
	if ( Pcuff>30) { pa=1; if (Pcuff>60) { pa=2; if (Pcuff>90) { pa=3; if (Pcuff>120) {  pa=4; } } } }
	if (pa!=pimage) {
		if (pimage>0){
			if (pimage==1) { u1cuff.style.visibility='hidden';  l1cuff.style.visibility='hidden'; }
			if (pimage==2) { u2cuff.style.visibility='hidden';  l2cuff.style.visibility='hidden'; }
			if (pimage==3) { u3cuff.style.visibility='hidden';  l3cuff.style.visibility='hidden'; }
			if (pimage==4) { u4cuff.style.visibility='hidden';  l4cuff.style.visibility='hidden'; }
		}
		pimage=pa;
		if (pa==4) { u4cuff.style.visibility='visible'; l4cuff.style.visibility='visible';   return; }
		if (pa==3) { u3cuff.style.visibility='visible';  l3cuff.style.visibility='visible';;  return; }
		if (pa==2) { u2cuff.style.visibility='visible';  l2cuff.style.visibility='visible';  return; }
		if (pa==1) { u1cuff.style.visibility='visible';  l1cuff.style.visibility='visible'; return; }
	}
}

function valvemove()
{
	var va=0;
	if (Verr>4) { va=5;} else { if (Verr>2) {va=4;} else { if (Verr>0) { va=3; } else { if (Verr>-2) {   va=2; } else { if (Verr>-4) { va=1; }}}}};  
	if (va!=vimage){
		if (mozilla){
			vimage=va;
			if (vimage==0) { va0.src='img/valve0.gif'; }
			if (vimage==1) { va0.src='img/valve1.gif'; }
			if (vimage==2) { va0.src='img/valve2.gif'; }
			if (vimage==3) { va0.src='img/valve3.gif'; }
			if (vimage==4) { va0.src='img/valve4.gif'; }
			if (vimage==5) { va0.src='img/valve5.gif'; }

		} else {
		if (vimage==0) { va0.style.visibility='hidden';}
		if (vimage==1) { va1.style.visibility='hidden';}
		if (vimage==2) { va2.style.visibility='hidden';}
		if (vimage==3) { va3.style.visibility='hidden';}
		if (vimage==4) { va4.style.visibility='hidden';}
		if (vimage==5) { va5.style.visibility='hidden';}
		vimage=va;
		if (vimage==0) { va0.style.visibility='visible'; }
		if (vimage==1) { va1.style.visibility='visible'; }
		if (vimage==2) { va2.style.visibility='visible'; }
		if (vimage==3) { va3.style.visibility='visible'; }
		if (vimage==4) { va4.style.visibility='visible'; }
		if (vimage==5) { va5.style.visibility='visible'; }
		}
	}
}

function stepsim(){
	Gp=Gp - (Gp - (Vset-Va)*0.05)*Tp;	// Autoregulation of flow
	var dpcuff;
	dpcuff=Pa-Pcuff;

	if (!mozilla){
		if ((Pcuff>10) || (pimage>0)) { cuffinflation();}
		if (cuffcount>0) {
			cuffcount--;
			if (cuffcount==48) bulbdraw(2);
			if (cuffcount==47) bulbdraw(3);
			if (cuffcount==46) bulbdraw(2);
			if (cuffcount==45) bulbdraw(1);
			if (cuffcount==44) bulbdraw(0);
			if ((cuffcount<46)&&(Pcuff>130)&&(textsel==1)){
				textsel=2;
				textout();
			}
		}
		if ((dpcuff<60) || (aimage>0) || (dimage>0)) { arteryocclude(dpcuff); }
		if ((servomode)||(vimage>0)) valvemove();
		if ((servomode)||(vimage>0)) valvemove();
	}
	i=0;
	while (i<8) {
		var dverr=(Math.random()-0.5)*2.5;
		if (Pref>0.5) {
			if (conventional) {
			 	Pref=Pref+dPref;
				if ((textsel==2) && (Vc>5)){
					textsel=3;
					Psys=Pcuff;
					textout();
				}
				if ((Pref < 65)&&(cuffcount<1)) { if (cuffinflate) togglecuff(); }
			}
		}
		if ((servomode)&&(!servoactive)) Pcuff=Pcuff+(Pref-Pcuff)*Tcuff;
		if (conventional) Pcuff=Pcuff+(Pref-Pcuff)*0.05;
		abp=abparray[simt];
		if (abp<0) {					// Signal that we are at the end of the array
			simt=0;
			if (x>xstop) {
				if (stopflag) {
					simulating=false;// If not continuous simulation, switch off after one pass
					stopflag=false;
					textline( '14px',lred,'Simulation Stopped'); 

				} else { x=0; }
			}
		} else {
			dVerr=dVerr+((Math.random()-0.5)*8 - dVerr )*0.2;
			for (j=0;j<8;j++) {		// Need extra iterations for segment under the cuff
				Vax=Vax+(abp-Pax)*Lax;
				dV=Vax-Va;
				Paxw=Paxw + dV*Cax;
				Pax=Paxw + dV*Dax;
				if (servoactive) Pcuff=Pservo;
				dp=Pa-Pcuff;
				c=Ca;
				dV=(Pax-Pa)*La;
				Va=Va+dV;
				Paw=Paw+(Va-Vc)*c;
				Pd=Pd+ (Va-Vc-Pd)*0.4;
				Pa=Paw+Pd*Da + 0.5*Pcuff;
				Gc=(Pa-Pcuff);
				if (Gc>10) { Gc=10;}
				if (Gc<0) { Gc=0; }
				Vc=Vc + ((Pa-Pb)*Gc-Vc)*0.1 ;
				Pbw=Pbw+(Vc-Vu)*Cb;
				Pb=Pbw+(Vc-Vu);
				Vdop=Va+dVerr;
				if (servomode){
					if (servoactive){
						Verr=Vdop-Vref;
						PIservo=PIservo+Verr*Ki;
						Pservo=Pservo+ (Verr*Kp + PIservo -Pservo)*Tservo ;
					} else { 
						PIservo=PIservo*0.99; 
						Pservo=PIservo;  
						if (Pref<50) { Verr=-10; } else { Verr=10; }
					}
				}
			}
// Underarm model:
			Vu=Vu+( Pb - Pu - Vu*Du)*Lu;
			Pu=Pu+(Vu - Gp*Pu)*Cu;
			i++;
			simt++;
// Transfer data to arrays used for display:
			//yp8[i]=y0-Pa*ky;
			yp8[i]=y0-Pax*ky;
			if (conventional) { yv8[i]=y0-Vc*vby;}	else 	{ yv8[i]=y0-Vdop*vay; }
			yc8[i]=y0-Pcuff*ky;
//			yc8[i]=y0-Pax*ky;
		}
	}
}

