////////////////////////////////////////////////////////////////////////////
//
//                       Copyright (c) 2006-2009
//                       Future Team Aps 
//                       Denmark
//
//                       All Rights Reserved
//
//   This source file is subject to the terms and conditions of the
//   Future Team Software License Agreement which restricts the manner
//   in which it may be used.
//   Mail: hve@hvks.com
//
/////////////////////////////////////////////////////////////////////////////
//
// Module name     :   Display function.js
// Module ID Nbr   :   
// Description     :   Javascript for polynomial interpolation
// --------------------------------------------------------------------------
// Change Record   :   
//
// Version	Author/Date		Description of changes
// -------  -------------	----------------------
// 01.01	HVE/06-Dec-18	Initial release
// 01.02	HVE/Nov-15-2009	Make the display function more recilient to abnormal numbers
// End of Change Record
//
/////////////////////////////////////////////////////////////////////////////

// Function argument checkking 
function check(args,func_name)
 {var actual=args.length; var expected=args.callee.length;
  if(actual!=expected) throw Error("Wrong number of arguments in function: "+func_name+"; Expected: "+expected+"; Actually passed "+actual); }
 
function autoscale_max(obj,xmin,xmax)
	{var i, resolve, ilow, ihigh, dx;
	 
	dx=Number(xmax-xmin); ilow=Number(xmin); ihigh=Number(xmax);resolve=dx/200;
	for(i=ihigh;;)
		{var last_i=i;
		if(obj.value(i)<resolve) {ihigh=i; i=Number(ilow)+(i-ilow)/2; } else
		if(obj.value(i)>resolve) {ilow=i; i+=Number((ihigh-ilow)/2); }
		alert("MAX:new i="+i.toFixed(1)+"["+ilow.toFixed(1)+","+ihigh.toFixed(1)+"]"+" resolve="+resolve.toFixed(3)+" f="+obj.value(last_i).toFixed(3)); 
		if(Math.abs(last_i-i)<0.1) break;
		resolve=(i-xmin)/200;
		} 
	return i;
	}
function autoscale_min(obj,xmin,xmax)
	{var i, resolve, ilow, ihigh, dx;	
	dx=Number(xmax-xmin); resolve=dx/200; ilow=Number(xmin); ihigh=Number(xmax);
	for(i=ilow;;)
		{var last_i=i;
		if(obj.value(i)<resolve) {ilow=i; i=Number(ihigh)+(i-ihigh)/2; } else
		if(obj.value(i)>resolve) {ihigh=i; i-=Number((ihigh-ilow)/2); }
		alert("MIN:new i="+i.toFixed(1)+"["+ilow.toFixed(1)+","+ihigh.toFixed(1)+"]"+" resolve="+resolve.toFixed(3)+" f="+obj.value(last_i).toFixed(3)); 
		if(Math.abs(last_i-i)<0.1) break;
		resolve=(i-xmin)/200;
		} 
	return i;
	}

function xxx()
	{
	
   dx=Number(xmax-xmin); ilow=Number(xmin); ihigh=Number(xmax);
	for(i=ihigh;;)
		{var last_i=i;
		if(Math.abs(obj.value(i))<xmax) {ilow=i; i=Number(ihigh)+(i-ihigh)/2; } else
		if(Math.abs(obj.value(i))>xmax) {ihigh=i; i-=Number((ihigh-ilow)/2); }
	//	alert("23:new i="+i.toFixed(1)+"["+ilow.toFixed(1)+","+ihigh.toFixed(1)+"]"+" xmax="+xmax.toFixed(3)+" f="+obj.value(last_i).toFixed(3)); 
		if(Math.abs(last_i-i)<0.1) break;
		} xmax=i;
   dx=Number(xmax-xmin); ilow=Number(xmin); ihigh=Number(xmax);
	for(i=ilow;;)
		{var last_i=i;
		if(Math.abs(obj.value(i))<xmax) {ihigh=i; i=Number(ilow)+(i-ilow)/2; } else
		if(Math.abs(obj.value(i))>xmax) {ilow=i; i+=Number((ihigh-ilow)/2); }
	//	alert("2:new i="+i.toFixed(1)+"["+ilow.toFixed(1)+","+ihigh.toFixed(1)+"]"+" xmax="+xmax.toFixed(3)+" f="+obj.value(last_i).toFixed(3)); 
		if(Math.abs(last_i-i)<0.1) break;
		} xmin=i;

	} 
// Graph the solutions
function graph_solution(jg,obj,xmin,xmax,form,integration,eq,dxmax,dxmin,dymax,dymin)
	{
	var i, j, co;
	var max_x, max_y, min_x, min_y, dx, dy;
	var resolve, ilow, ihigh;
	var xptrs=new Array;
	var yptrs=new Array;
	
	jg.clear();
	if(isNaN(parseFloat(dxmax))) dxmax=Number.POSITIVE_INFINITY; 
	if(isNaN(parseFloat(dxmin))) dxmin=Number.NEGATIVE_INFINITY; 
	if(isNaN(parseFloat(dymax))) dymax=Number.POSITIVE_INFINITY; 
	if(isNaN(parseFloat(dymin))) dymin=Number.NEGATIVE_INFINITY; 
	xmax=Math.min(dxmax,xmax);
	xmin=Math.max(dxmin,xmin); //alert(xmax+":"+xmin+";"+dxmax+":"+dxmin);
	dx=Number(xmax-xmin);
	for( i=Number(xmin), j=0;i<=Number(xmax);i+=Number(dx/100),j++)
		{var v;
		try{v=obj.value(i);}
		catch(e){alert(e);return;}
		if(isFinite(v)==false) { alert("Display: expression evaluates to "+yptrs[j]+" for x="+i); j-- }
		else if(dymin<=v&&dymax>=v) {xptrs[j]=i; yptrs[j]=v; }
		}
	max_x=max_y=-Infinity;
	min_x=min_y=+Infinity;
	for(i=0;i<yptrs.length;i++)
		{ 
		if(max_x<xptrs[i]) max_x=xptrs[i];
		if(min_x>xptrs[i]) min_x=xptrs[i];
		if(max_y<yptrs[i]) max_y=yptrs[i];
		if(min_y>yptrs[i]) min_y=yptrs[i];
		}
	max_x++; min_x--;max_y++; min_y--;
	max=max_x; mix=min_x;
	max_x=Math.max(max_x,max_y); min_x=Math.min(min_x,min_y);
	max_y=max_x; min_y=min_x;		
	max_x=Math.ceil(max_x); min_x=Math.floor(min_x);
	max_y=Math.ceil(max_y); min_y=Math.floor(min_y);
	dx=max_x-min_x; dy=max_y-min_y;
	if(dx==0&&dy==0) {max_x=+1, min_x=-1; max_y=1; min_y=-1; dx=2; dy=2 }
	co=new Coordinate(jg,400,400,Number(min_x), Number(min_y), Number(max_x), Number(max_y), Math.ceil(dx/10), Math.ceil(dy/10),false,false);
	co.addTitle("Function Graphing of "+eq);
	jg.setColor("#00ff00");
	jg.setStroke(2);
	if(integration)
		{
		xptrs[xptrs.length]=xptrs[xptrs.length-1]; yptrs[yptrs.length]=0;
		xptrs[xptrs.length]=xptrs[0]; yptrs[yptrs.length]=0;
		xptrs[xptrs.length]=xptrs[0]; yptrs[yptrs.length]=yptrs[0];
		co.fillPolygon(xptrs,yptrs);
		}
	else co.drawPolyline(xptrs,yptrs); 
	jg.setStroke(1);jg.setColor("#000000");
	co.paint();
	}
// Graph the solutions
function graph_convergence(jg,form,eq,objects)
	{
	var i, j, co;
	var max_x, max_y, min_x, min_y, dx, dy;
	var resolve, ilow, ihigh;
	var xptrs=new Array;
	var yptrs=new Array;
	var color=new Array;
	
	jg.clear(); 
	for(var i=0, max_x=0;i<objects.length;i++) max_x=Math.max(max_x,objects[i].q.length+2);
	for(var i=0, max_y=0;i<objects.length;i++) for(var j=0;j<objects[i].q.length;j++) max_y=Math.max(max_y,objects[i].q[j]);
	min_x=0; min_y=0;
	dx=Number(max_x-min_x);
	max=max_x; mix=min_x;
	max_x=Math.max(max_x,max_y); min_x=Math.min(min_x,min_y);
	max_y=max_x; min_y=min_x;		
	max_x=Math.ceil(max_x); min_x=Math.floor(min_x);
	max_y=Math.ceil(max_y); min_y=Math.floor(min_y);
	dx=max_x-min_x; dy=max_y-min_y;
	if(dx==0&&dy==0) {max_x=+1, min_x=-1; max_y=1; min_y=-1; dx=2; dy=2 }
	co=new Coordinate(jg,400,400,Number(min_x), Number(min_y), Number(max_x), Number(max_y), Math.ceil(dx/10), Math.ceil(dy/10),false,false);
	co.addTitle("Convergence power of "+eq);
	co.addXname("i"); co.addYname("q");
	color[0]="#ff0000"; color[1]="#00ff00"; color[2]="#0000ff"; color[3]="#ffff00";
	color[4]="#ff00ff"; color[5]="#00ffff"; color[6]="#0fff00"; color[7]="#00fff0";
	for(var i=0;i<objects.length;i++)
		{var obj=objects[i];		co.addLegend(color[i],obj.method()); xptrs.length=0; yptrs.length=0;
		for( var k=0,j=0;k<obj.q.length;j++,k++){xptrs[j]=k+2; yptrs[j]=obj.q[k]; }
		jg.setColor(color[i]);
		jg.setStroke(2);
		co.drawPolyline(xptrs,yptrs); 
		jg.setStroke(1);jg.setColor("#000000");
		}
	co.paint();
	}
// Graph the solutions
function graph_delta(jg,form,eq,objects)
	{
	var i, j, co, last;
	var max_x, max_y, min_x, min_y, dx, dy;
	var resolve, ilow, ihigh;
	var xptrs=new Array;
	var yptrs=new Array;
	var color=new Array;
	
	jg.clear(); 
	for(var i=0, max_x=0;i<objects.length;i++) max_x=Math.max(max_x,objects[i].i.length);
	for(var i=0, max_y=0;i<objects.length;i++) for(var j=0,last=0;j<objects[i].i.length;j++) {max_y=Math.max(max_y,Math.abs(objects[i].i[j]-last)); last=objects[i].i[j];}
	for(var i=0, min_y=Number.POSITIVE_INFINITY;i<objects.length;i++) for(var j=0,last=0;j<objects[i].i.length;j++) {min_y=Math.min(min_y,Math.abs(objects[i].i[j]-last)); last=objects[i].i[j];}
	
	min_x=0; if(min_y==0) min_y=1E-20;
	dx=Number(max_x-min_x);
	max=max_x; mix=min_x;
//	alert("Linear "+max_y+":"+min_y);		
	max_y=Math.LOG10E*Math.log(max_y); min_y=Math.LOG10E*Math.log(min_y);
//	alert("log "+max_y+":"+min_y);		
	max_x=Math.ceil(max_x); min_x=Math.floor(min_x);
	max_y=Math.ceil(max_y); min_y=Math.floor(min_y);
	dx=max_x-min_x; dy=max_y-min_y;
	if(dx==0&&dy==0) {max_x=+1, min_x=-1; max_y=1; min_y=-1; dx=2; dy=2 }
	//alert(min_x+";"+min_y+";"+max_x+";"+max_y); 
	co=new Coordinate(jg,400,400,Number(min_x), Number(min_y), Number(max_x), Number(max_y), Math.ceil(dx/10), Math.ceil(dy/10),false,true);
	co.addTitle("Delta of "+eq);
	co.addXname("i"); co.addYname("dx");
	color[0]="#ff0000"; color[1]="#00ff00"; color[2]="#0000ff"; color[3]="#ffff00";
	color[4]="#ff00ff"; color[5]="#00ffff"; color[6]="#0fff00"; color[7]="#00fff0";
	for(var i=0;i<objects.length;i++)
		{var obj=objects[i];	co.addLegend(color[i],obj.method()); xptrs.length=0; yptrs.length=0;
		for(var k=0,j=0, last=0;k<obj.i.length;j++,k++) if(obj.i[k]!=0) {xptrs[j]=k; yptrs[j]=Math.max(Math.abs(obj.i[k]-last),1E-19); last=obj.i[k]; }
		jg.setColor(color[i]);
		jg.setStroke(2);
		co.drawPolyline(xptrs,yptrs); 
		jg.setStroke(1);jg.setColor("#000000");
		}
	co.paint();
	}


var jg = new jsGraphics("theCanvas");
var jg2 = new jsGraphics("theCanvas2");
var jg3 = new jsGraphics("theCanvas3");

// Evaluate and parse the equation. If OK then soilve the equation and print the result
function displayit(form)
	{var integration, xmin, xmax, eq, verbose, obj;
	eq=form.equation.value;
	xmin=form.Xmin.value;
	xmax=form.Xmax.value;
	if(xmax==+Infinity) xmax=Number.MAX_VALUE;
	if(xmin==+Infinity) xmin=Number.MAX_VALUE;
	if(xmax==-Infinity) xmax=-Number.MAX_VALUE;
	if(xmin==-Infinity) xmin=-Number.MAX_VALUE;
	dxmax=form.XMax.value;
	dxmin=form.XMin.value;
	dymax=form.YMax.value;
	dymin=form.YMin.value;

	obj=new Integration(eq);
	if(true)
		graph_solution(jg,obj,xmin,xmax,form,integration,eq,dxmax,dxmin,dymax,dymin);
	}

function DisplayVerbose(form,verbose,obj)
	{
	if(verbose) 
		{var n;
		form.Display.value+="   %-10s %-5s %-20s %s".sprintf("Iteration","N","Value","Convergence Power")+"\n";
		for(var i=0,n=1;i<obj.i.length;n*=2,i++)
		form.Display.value+="        %2d    %-5s %-20s %s".sprintf(i+1,n.toString(),obj.i[i].toString(),i<2?"":obj.q[i-2],i>0?Number((obj.i[i]-obj.i[i-1])).toExponential(0):"")+"\n";
		form.Display.value+="\n";				
		}
	}

function testfunction(form)
	{
	if(form.GaussHermite.checked) { 	form.equation.value='exp(-2*x*x)'; form.Xmin.value='-Infinity';form.Xmax.value='+Infinity'; 
	form.Display.value+="Integeration of "+form.equation.value+" in ["+form.Xmin.value+","+form.Xmax.value+"] is 1.253314137"+"\n"; }
	else if(form.GaussChebyshev.checked) { form.equation.value='exp(x)/sqrt(1-x*x)'; form.Xmin.value='-1';form.Xmax.value='+1';
	form.Display.value+="Integeration of "+form.equation.value+" in ["+form.Xmin.value+","+form.Xmax.value+"] is 3.9774632605"+"\n";}
	else if(form.GaussLegendre.checked) { form.equation.value='1/(1+x)';form.Xmin.value='0';form.Xmax.value='1'; 
	form.Display.value+="Integeration of "+form.equation.value+" in ["+form.Xmin.value+","+form.Xmax.value+"] is 0.6931471806"+"\n";}
	else if(form.Romberg.checked) { form.equation.value='sqrt(x)';form.Xmin.value='0';form.Xmax.value='0.5'; 
	form.Display.value+="Integeration of "+form.equation.value+" in ["+form.Xmin.value+","+form.Xmax.value+"] is 0.23570226"+"\n";}
	else if(form.FoxRomberg.checked) { form.equation.value='1/sqrt(x)';form.Xmin.value='0';form.Xmax.value='0.5'; 
	form.Display.value+="Integeration of "+form.equation.value+" in ["+form.Xmin.value+","+form.Xmax.value+"] is 1.4142135624"+"\n";}
	else if(form.DoubleExponential.checked) { form.equation.value='log(x)*sqrt(x)';form.Xmin.value='0';form.Xmax.value='1.0'; 
	form.Display.value+="Integeration of "+form.equation.value+" in ["+form.Xmin.value+","+form.Xmax.value+"] is -.444444444444"+"\n";}
	else{ form.equation.value='x*x+2';form.Xmin.value='-2';form.Xmax.value='4'; 
	form.Display.value+="Integeration of "+form.equation.value+" in ["+form.Xmin.value+","+form.Xmax.value+"] is 36"+"\n";}
	}
	log(x)*sqrt(x)
// Evaluate and parse the equation. If OK then soilve the equation and print the result
function solveit(form)
	{var integration, xmin, xmax, eq, verbose, obj,objects;
	eq=form.equation.value;
	verbose=form.Verbose.checked;
	if(verbose) form.Display.rows=10; else form.Display.rows=5; 
	xmin=form.Xmin.value;
	xmax=form.Xmax.value;
	if(xmax==+Infinity) xmax=Number.MAX_VALUE;
	if(xmin==+Infinity) xmin=Number.MAX_VALUE;
	if(xmax==-Infinity) xmax=-Number.MAX_VALUE;
	if(xmin==-Infinity) xmin=-Number.MAX_VALUE;
	dxmax=form.XMax.value;
	dxmin=form.XMin.value;
	dymax=form.YMax.value;
	dymin=form.YMin.value;
	objects=new Array;
	
	obj=new Integration(eq);
	if(form.Trapez.checked||form.Simpson.checked||form.Romberg.checked||form.FoxRomberg.checked||form.GaussLegendre.checked||form.GaussChebyshev.checked||form.GaussHermite.checked||form.DoubleExponential.checked) integration=true; else integration=false;
	//if(isNaN(parseFloat(dxmax))) {dxmax=autoscale_max(obj,xmin,xmax); form.XMax.value=dxmax;} 
	//if(isNaN(parseFloat(dxmin))) {dxmin=autoscale_min(obj,xmin,xmax); form.XMin.value=dxmin;}

	if(true)
		{
		graph_solution(jg,obj,xmin,xmax,form,integration,eq,dxmax,dxmin,dymax,dymin);
		if(integration)
			{
			form.Display.value+="\nNumerical Integration of %s in the interval [%s,%s]".sprintf(eq,form.Xmin.value,form.Xmax.value)+"\n";
			form.Display.value+="%-16s%-25s%-25s".sprintf("Method","Value","Estimated Error")+"\n";
			form.Display.value+="--------------------------------------------------------------------------\n";
			}
		if(form.Trapez.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Trapez",obj.trapez(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj);  objects[objects.length]=obj;
			}
		if(form.Simpson.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Simpson",obj.simpson(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj); objects[objects.length]=obj;
			}
		if(form.Romberg.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Romberg",obj.romberg(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj); objects[objects.length]=obj;
			}
		if(form.FoxRomberg.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Fox-Romberg",obj.foxromberg(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj); objects[objects.length]=obj;
			}
		if(form.GaussLegendre.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Gauss-Legendre",obj.gausslegendre(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj); objects[objects.length]=obj;
			}
		if(form.GaussChebyshev.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Gauss-Chebyshev",obj.gausschebyshev(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj); objects[objects.length]=obj;
			}
		if(form.GaussHermite.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Gauss-Hermite",obj.gausshermite(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj); objects[objects.length]=obj;
			}
		if(form.DoubleExponential.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Double Exp",obj.doubleexponential(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj); objects[objects.length]=obj;
			}
/*		if(form.DoubleExponential.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Double Exp2",obj.doubleexponential2(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj); objects[objects.length]=obj;
			}*/
/*		if(form.DoubleExponential.checked) 
			{var obj=new Integration(eq);
			form.Display.value+="%-16s%-25s%-25s".sprintf("Double Exp3",obj.doubleexponential3(xmin,xmax).toString(),obj.accuracy)+"\n";
			DisplayVerbose(form,verbose,obj); objects[objects.length]=obj;
			}*/
		if(integration) { graph_convergence(jg2,form,eq,objects);  graph_delta(jg3,form,eq,objects); }
		}
	}
	

function reset_textarea(form)
	{
	form.Display.value="";
	jg.clear();
	jg2.clear();
	jg3.clear();
	}
function save_textarea(form)
	{
//	form.Display.value.print();
	}

function print_textarea(form)
	{
	var printing=form.Display.value;
	newWindow=null;
	newWindow=window.open("","newWin","toolbar=yes,location=yes,menubar,status,toolbar,scrollbars=yes,width=400,height=400,resizable=yes");
    newWindow.document.write('<html>\r\n\r\n');
    newWindow.document.write('<head>\r\n');
    newWindow.document.write('<meta http-equiv="Content-Language" content="en-us">\r\n');
	newWindow.document.write('<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">\r\n');    
    newWindow.document.write('<title>Web based Polynomial root finder result</title>\r\n');
    newWindow.document.write('</head>\r\n\r\n');
    newWindow.document.write('<body>\r\n');
//    newWindow.document.write('<form><input type="button" value="Print This Page" onClick="javascript:window.print();" /></form>');
    newWindow.document.write('<a href="javascript:window.print();">Print This Page</a>');
    newWindow.document.write('\t');
    newWindow.document.write('<a href="javascript:window.close()">\tClose This Page </a>');
    newWindow.document.write('<pre>\r\n');
    newWindow.document.write(printing);
    newWindow.document.write('</pre>\r\n');
    newWindow.document.write('</body>\r\n\r\n');
    newWindow.document.write('</html>');
	}


