/*
GBgraph routines
TBD :try me with IE excanvas.compiled.js 
*/
var gVersion = '1.8.0';
var gDebug = 0;
var iNited = 0; // one time init
var gLine ; // The line graph object
var wantsAn = 1; // sometimes(plotting) we do not need a[n]
var wantsBn = 1; // sometimes b[n] is automatically computed
var wantsLine = 1; // clears the line graph and redraws

var ldata = new Array(101); // array to draw canvas - scaled
var adata = new Array(101); // a[n] not scaled
var odata = null; // b[n] scaled
var bdata = new Array(101); // b[n]
var aList ; // glob for user
var uMark ; // user marks
var gList = new Array();  // array of [x,y] to draw


var aTimer;
var tInterval= 256 ; // m-sec
var d0 ; // init start date

var stopped= 1; // 0 = animating - 1 = stopped -  2 = step by step
var tDisp ; // a[n] display ...
var tDisp2 ; // a[nMin] display ...
var cDisp;  // canvas display
var mDisp; // mouse  or trace diplay
var commentDisp; // comment display
var lPos = new Array(4); // coordinates of cDisp object;
var jExpr; // user java
var vExpr; // internal translated
var gError = 0;
var inInit; var inFinish ;// USER PROLOGUE/EPILOGUE

// THE FOLLOWING  globs may be modified by the user
var gReg = 0;    // wants regression
var gSpline = 0; // wants spline approx
var gAnim = 1;   // wants anims
var aCacheDim = 10000 ; // recursive seq's
var gInt = 1; // assume integer sequence
var nMin = 0; // drawing from [nMin to nMin+nSteps]
var onMin = 0; // save value for scroll
var nSteps = 100;
var onSteps = 100; // save value
var gStyle = 1; // 1 = line - 2 = bar
var xMax = 0; // plotting only
var yMax = 0; //  if(0) = computed into gMax
var gMax = 1; // line.max or bar.max  - COMPUTED AFTER FIRST draw()
var yMin = 0;
var xAxis = 0; // 1 = center
var yAxis = 0; // 1 = center
var yScale = 0;
var yLog = 0;
var gUtter = 10;
var nMult = 1; // adata[i] = a[(i*nMult) + nMin]
var onMult= 1;
var gCross = 0;
var lWidth=1;
var gTick = 'cross' ;
var gMark = 'filledcircle' ;
var gMarkColor = 'blue' ;
var gTickSize= 3;
var gTickColor = 'red' ;
var gVariant = 'dot';
var gColor = 'red' ;
var bColor = '#ffffee' ;
var bScroll= 1;
var gFrame = 0;  // 1 = framing - no scroll
var nFrame = 1;  // starts at 1 if animation
var gTitle = null;
var nFrameMax = 0;
// line only
var gStepped=0;
var gFilled = 0;
var fColor = 'yellow' ;

/*------------
Ticks list
-------------------*/
var lTick = 
 ['dot', 'circle', 'filledcircle', 'endcircle', 'square', 'endsquare', 'filledsquare',
 'filledendsquare', 'tick', 'halftick', 'endtick', 'cross', 'borderedcircle', 'arrow', 'filledarrow'] ;

var lColor = new Array();

function fillcolors()
{
clr=new Array('00','20','40','60','80','a0','c0','ff');
for (var i=0;i<8;i++) 
for (var j=0;j<8;j++) 
for (var k=0;k<8;k++) 
	lColor.push('#'+clr[i]+clr[j]+clr[k]);
//alert(lColor);
}
fillcolors();


/*----------------------------
params() - display params
----------------------------------*/
var tgStyle =["","1 - Line","2 - Bar"];
function params()
{
var txt = '';

txt += 'gInt = ' + gInt + '\n' ;
txt += 'n    in [' + onMin + '...' + (nSteps*nMult + onMin) +"]\n\n";


txt += 'gTitle = ' + gTitle + '\n' ;
txt += 'gStyle = ' + tgStyle[gStyle]  + '\n';
txt += 'lWidth = ' + lWidth  + '\n';
if(gStyle == 1)
{
txt += 'gStepped = ' + gStepped  + '\n';
txt += 'gFilled = ' + gFilled  + '\n';
txt += 'fColor = ' + fColor  + '\n';
txt += 'gTickColor = ' + gTickColor  + '\n';
}
txt += 'bColor = ' + bColor  + '\n';
txt += 'gColor = ' + gColor + "\n\n";
txt += 'nMin = ' + nMin  + '\n';
txt += 'nSteps = ' + nSteps + '\n';
txt +=  'nMult = ' + nMult + '\n';
txt +=  'xAxis = ' + xAxis + ' (1 = center)\n\n';

txt += 'xMax = ' + xMax + '\n';
if(yMax == 0)
txt += 'yMax = ' + gMax + ' (computed)\n';
else
txt += 'yMax = ' + yMax + '\n';
txt +=  'yAxis = ' + yAxis + ' (1 = center)\n';
txt += 'yMin = ' + yMin + '\n';
txt += 'yScale = ' + yScale + '\n';
txt += 'yLog = ' + yLog + '\n\n';

txt += 'gFrame = ' + gFrame +'\n';
txt += 'nFrame = ' + nFrame + '\n';
txt += 'nFrameMax = ' + nFrameMax + '\n';
txt += 'tInterval = ' + tInterval + ' (msec)\n';

if(gDebug)
	{
	txt += '\ngIter = ' + gIter +'\n';
	}
txt += '\n See [Help]';
alert(txt);
} // params

/*-----------------------------
inverse function NOT HERE  !!
returns y such as f(x) = y 
---------------------------------------*/
function inv(f,x,ymin,ymax)
{
if(arguments.length < 4)
	{
	ymax = 1000 ; // good luck
	if(yMax) ymax = yMax;
	}
if(arguments.length < 3)
	{
	ymin = 0;
	if(xAxis) ymin = - ymax ;
	}
return _inv(f,x,ymin,ymax);
} //inv
	
/*----------------------------
comment ('txt')
---------------------------------*/
function comment(txt)
{
commentDisp.innerHTML = '' + txt;
}

/*----------------------------
reset()
-------------------------*/
function reset()
{
	resetCanvas(cDisp); // turn on Canvas if image drawn
	//comment(''); commentDisp not defined at boot time
	mtime(0);
	stopped=1;
	gReg= 0;
	gSpline = 0;
	gList = null;
	wantsAn = wantsBn = 1;
	wantsLine= 1;
	inInit= inFinish=0;
	gDebug = 0;
	
if(arguments.length)
	{
	gStyle= 1;
	gTick = 'cross';
	gTickSize=3;
	gTickColor='red';
	gVariant = 'dot';
	gColor = 'red';
	bColor = '#ffffee' ;
	fColor = 'yellow' ;
	tInterval = 256;
	gMark = 'filledcircle' ;
        gMarkColor = 'blue' ;
	}
	
	gInt = 1;
	gError=0;
	yMax = xMax = 0; //  0 = computed
	yMin = 0;
	xAxis= yAxis = 0; //  1 = center
	nMin = 0; // ldata[i] = a(i*nMult+nMin)
	yLog = yScale = 0;
	nMult=1;
	nSteps=100 ;
	gStepped = gFilled = gCross = 0;
	lWidth=1;
	
	bScroll = 1;
	gAnim = 1;
	gFrame = 0 ;
	nFrame=1 ;
	nFrameMax = 0;
	gTitle= null;
} // reset


/*-------------------------------------
 - ON MOUSEMOVE in canvas
--------------------------------*/
function trackmouse(e)
{
var i,x,ihit;
var dx = (lPos[1] - gUtter*2) /nSteps;
var b_hit;
var txt;

	if(!lPos[0]) return;
	var posx = 0; // mouse
	var posy = 0;

	if (!e) var e = window.event;
	if (e.pageX || e.pageY)
		{
		posx = e.pageX;
		posy = e.pageY;
		}
	else if (e.clientX || e.clientY)
		{
		posx = e.clientX + document.body.scrollLeft
			+ document.documentElement.scrollLeft;
		posy = e.clientY + document.body.scrollTop
			+ document.documentElement.scrollTop;
		}

	if(posy < lPos[2]) return;
	if(posy > lPos[2] + lPos[3]) return;

 if (wantsAn == 0) // plotting
		{
		posx -= (lPos[0] + gUtter) ;
		posy -= (lPos[2] + gUtter) ;
		posx /= (lPos[1] - 2*gUtter);
		posy /= (lPos[3] - 2*gUtter);
		if(posx <0 || posx>1 || posy <0 || posy > 1) return;
		posy = 1 - posy;
		if(yAxis) {posx -= 0.5 ; posx *= 2*xMax;} else posx *= xMax;
		if(xAxis) {posy -= 0.5;  posy *= 2*yMax;} else posy *= yMax;

		txt = '[' +format(posx)+ ', ' + format(posy) + ']' ;
		mDisp.innerText = mDisp.textContent = window.status = txt ;
		return;
		}
		
// compute i index in adata[]

		posx -= (lPos[0] + gUtter) ;
		i = Math.floor(posx/dx + 0.5)  ;
		if(i > nSteps) i= nSteps; if( i < 0) i = 0;
		
		if(adata[i] == undefined) txt ='';
		else
 		{
 		var idx = format(((i*nMult)+onMin)) ;
		txt = "a[" + idx + "] = " + format(adata[i]);
for(var u=0; u < uMark.length; u++)
	if(idx == uMark[u][0]) {txt += ' * '; break;}
		if(odata != null)
		txt += "   b[" + idx + "] = " + format(bdata[i]);
		if(yLog || yScale) txt += "  |  y[" + idx + "] = " + format(ldata[i]);
		}
		
mDisp.innerText = mDisp.textContent =
window.status = txt ;
} // trackmouse

document.onmousemove = trackmouse ;

/*-------------------------------------
drawmark(x,y)
----------------------------------------*/
function drawmark(x,y)
{
var xmax,ymax;
// scale (x,y) into [0,1]
var w = (lPos[1] - 2 *gUtter);
var h = (lPos[3] - 2 *gUtter);

if(wantsAn)
	{
	x -= onMin; // scrolling
	y -= yMin;  
	ymax = gMax;
	xmax = nMult*nSteps;
	x /= xmax;
	}
	else 
	{
	xmax= xMax;
	ymax =yMax;
	if(yAxis) { x += xmax; x /= (2*xmax);} else x /= xmax;
	}
        if(xAxis) { y += ymax; y /= (2*ymax);} else y /= ymax;
	x = gUtter + w*x;
	y = gUtter + (1-y)*h;
if(x < gUtter) return;	
gLine.DrawTick(x,y,gMarkColor,false);
}
	
/*------------------------------------
findPos
------------------------------------------*/
function findPos(obj)
		{
		var curleft = curtop = height = width = 0;
		height = obj.offsetHeight;
		width = obj.offsetWidth;
		if (obj.offsetParent)
		do {
				curleft += obj.offsetLeft;
				curtop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	return [curleft,width,curtop,height] ;
} // findPos

/*----------------------------------
pulse(p)
uses nFrame
nFrame == 1 -> pulse = 1

----------------------------*/
function pulse (p) {if(p<=1) p=1.1; return 1 +sin((nFrame-1)*PI/p)/p;}

/*---------------------------
speed
------------------------------------*/

function speed(delta)
{
if(delta > 0) tInterval /= 2;
else tInterval *= 2 ;
if(tInterval < 2) tInterval = 2;
if(tInterval > 4096) tInterval = 4096;
window.status = 'freq: ' + tInterval + ' (ms)';
}

/*-----------------------------------------
display a[n]
-----------------------------------------*/
function display(n,an_,bn_)
{
	var dtxt ;
	
	if(wantsAn == 0) // plotting
	dtxt = "xMax = " + format(xMax) + " | yMax = " + format(yMax) ;
	else
	{
	dtxt = "a[" + format(n) + "] = " + format(an_) ;
	if(bn_ != undefined)
	dtxt += "  b[" + format(n) + "] = " + format(bn_) ;
	
	// if(yLog || yScale) dtxt += " | y[" + n + "] = " + scale(an_);
	if(gMax != an_) dtxt += " | yMax = " + format(gMax);
	}
	tDisp.innerText = tDisp.textContent = window.status = dtxt ;
}

/*-----------------------------------------
interval(nfrom,nto)  : sets nMult f(gInt)
----------------------------------------*/
var nStepsMax = 1000;
function interval(nfrom,nto,nsteps)
{
if(!inInit) return;
if(nto <= nfrom) {trace('Bad Interval '+ nfrom + ' ' + nto); nMin=0;nMult=1; return;}
if(arguments.length == 3) nSteps = nsteps; if(nSteps <= 1) nSteps = 100;

if(nfrom == -nto) yAxis = 1; // center
nMin = nfrom;
nMult = (nto-nfrom)/nSteps ;

// try to me smart to find gInt
if(!isint(nfrom) || ! isint(nto) || !isint(yMax) || nMin < 0 /**HARSH!!*/) gInt = 0 ;
if(gInt == 0) return ; // any nMult

if(arguments.length == 3 // nSteps specified
||
(nto - nfrom) > nStepsMax )
	{
	nMult = Math.floor(nMult); 
	nto = nfrom + nSteps*nMult;
	return;
	}
// find a good nSteps
nMult=1 ; 
nSteps = nto - nfrom; 
return;
} // interval

//
// cache last computed value - fibo,....
//
var acache ;  // array (10000)
var bcache ;
/*----------------------------------------------
A SEQUENCE : sequence definition a(n) :
replaced a[xxx] by a(xxx)
returns [a[n],b[n]]
-----------------------------------------------------*/
function a(n) {
var txt;
var an_ = undefined ;
var bn_ = undefined ;
var incache = false;


if(gError) return [1,undefined];
if( n < nMin ) // recursive fail
	{
	txt = "Error in recursive call?\n\n" + "a[0] = " + adata[0];
	txt += "\nn = " + n +"\nnMin = " + nMin;
	alert(txt);
	gError=3;
	stopped=1;
	return [1,undefined];
	}

if(wantsAn)
if(n >= 0 && n < aCacheDim && floor(n) == n ) // n integer !!
	{
	incache = true;
	if(acache[n] != undefined) return [acache[n],bcache[n]];
	}
	
try
{
eval(vExpr); // EVAL an_, bn_ 
}
catch(err)
	{
	txt="Error in Java expression\n\n" + vExpr + "\n\n"; 
	if(err.description != undefined) txt+="Error: " + err.description + "\n\n";
	else if (err.message != undefined) txt+="Error: " + err.message + "\n\n";
	txt+= "at  n = " + n;
	alert(txt);
	gError=1;
	stopped=1;
	window.status = vExpr;
	return [1,undefined];
	}

	if(aList != null) // sets by user
	{
	if(inInit) {nMin=0; nSteps = aList.length-1; nMult=1;}
	if(n >= 0 && n < aList.length) return [aList[n],bn_] ;
	}
	
	if(inInit)
	if(n == 0 && nMin != 0) return a(nMin);
	
	if(yMax && an_ == Infinity)  an_ =  2*yMax; // gMax not yet known..
	if(yMax && an_ == -Infinity) an_ = -2*yMax;

	if(aList != null && an_ == undefined) return[0,undefined];
	if(gList.length > 0) {wantsAn = 0;gFrame=1;}
	if(!wantsAn) return [0,undefined] ;

if(isNaN(an_) || an_ == undefined || an_ == Infinity || an_ == -Infinity )
	{
	txt="Undefined a[n]\n\n" + vExpr + "\n\n"; // jExpr for end user ! FIX ME
	txt+= "at  n = " + n;
	txt+= "\na[n] = " + an_; // DBG
	txt+= "\ngInt = " + gInt;
	alert(txt);
	stopped=1;
	gError = 2;
	window.status = vExpr; // internal info
	return [1,undefined];
	}

// cache ops
	
	if(!inInit)
	if (incache) {acache[n] = an_ ; bcache[n] = bn_;}

return [an_ , bn_];
} // aseq


/*----------------------
scaling
--------------------------*/
function scale(y)
{
if(y == undefined) y = 0;
y -= yMin;
if(yScale) y /= yScale;
if(yLog ) y = mylog(y);
return y;
}


/*--------------------------
mtime() - milliseconds from last init
--------------------------------*/
function mtime()
	{
	var d ;
	if(arguments.length) d0 = new Date();
	d = new Date();
	return d.getTime() - d0.getTime();
} // mtime

/*-------------------------
mark
------------------------------*/
function mark(x,y)
{
uMark.push([x,y]);
}

/*-------------------------
drawmarks
----------------------------*/
function drawmarks()
{
for(var i = 0; i<uMark.length;i++) drawmark(uMark[i][0],uMark[i][1]);
}

/*-------------------------
init 
------------------------------*/
function init()
{
var i = 0;
var an;
var b0 = false;

if(iNited == 0) //
{
tDisp  = document.getElementById('TDISP');   // a[n]
tDisp2  = document.getElementById('TDISP2'); // a[0] display
cDisp =  document.getElementById('CDISP'); // Canvas itself
mDisp =  document.getElementById('MDISP'); // Canvas mouse in
commentDisp = document.getElementById('COMMENT');

iNited=1;
stopped = 1;
lPos[0] = 0;
lPos = findPos(cDisp);
}

gError=0;
gReg = 0; // no regression

comment('');
tDisp2.innerText = tDisp2.textContent =
tDisp.innerText =  tDisp.textContent = "";

// starting ldata
	acache = new Array(aCacheDim);
	bcache = new Array(aCacheDim);
	resetcaches(); // math
	
	adata[0] =  adata[1] = undefined;
	bdata[0] =  bdata[1] = undefined;
	aList = null ; // user array may be
	uMark = new Array();// user Marks
	//gList = new Array();//to drawgraph
	
// trick - compute a(0) to check syntax and set some globals (nMin, nSteps)
	if(stopped == 1 || wantsAn == 0) // PROLOGUE
	{
gList = new Array();
	odata = null; // no b sequence
	inInit = 1; 
	an = a(0);  // or a(nMin) if set by user
	if(an[1] != undefined) 
			{
			gStyle=1; // force
			odata  = new Array(nSteps+1); 
			bdata = new Array(nSteps+1); 
			}
	if(adata.length != nSteps+1)
		{
		ldata = new Array(nSteps+1);
		adata = new Array(nSteps+1);
		}
	inInit = 0; 
	} // END PROLOGUE
	
	if(wantsAn == 0) // reset by plot,polar,..or entering gList
		{
		if(nFrame > 1)
		tDisp2.innerText = tDisp2.textContent =  ' nFrame = ' + nFrame ;
		return; 
		}
	
	if(gSpline)
	if(stopped == 0 || stopped == 2)
	{nSteps = onSteps; nMult= onMult; nMin = onMin;}
	
	if(yMax) yMax = scale(yMax);
	if(gError) return;
	if(nSteps <= 0) nSteps = 2;
	if(nSteps > nStepsMax) nSteps = nStepsMax;
	{onSteps = nSteps; onMult= nMult; onMin = nMin;} // for scroll

	xAxis=0;
	resetcaches(); // math
	mtime(0);
	
	adata.length = nSteps+1; // in case scrambled by gSpline; 
	ldata.length = nSteps+1;
	
for(i=0;i<=nSteps;i++)
	{
	if(i == nSteps) inFinish = 1; //  EPILOGUE - may reset wantsBn 
	an = a((i*nMult)+nMin) ; 
	inFinish =0;
	
if(gInt && !isint(an[0])) {reset(); gInt=0 ;init(); return;} // RISKY BUT WORKS
	adata[i] = an[0];
	ldata[i] = scale(adata[i]); if(ldata[i] < 0) xAxis = 1 ; 
	
	if(wantsBn)
	if(odata) 
		{
		bdata[i] = an[1];
		odata[i] = scale(bdata[i]);  
		if(odata[i] < 0) xAxis=1 ;
		}
		else bdata[i] = undefined;
		
	if(gError) break;
	}
	
	
	if(gSpline) dospline(gSpline); // gSpline = 1 into odata[], bdata[]
				       // gSpline = 2 into adata[], ldata[]
	if(gReg) _regression(ldata); // into odata[], bdata[]
	
	{
	var txt = "a[" + format(nMin)  + "] = " + format(adata[0]);
	if(nFrame > 1) txt += ' nFrame = ' + nFrame ;
	tDisp2.innerText = tDisp2.textContent =  txt ;
	}
} // init


/*---------------------------------------------------
windraw
----------------------------------------------------*/
function windraw()
        {
        var i;
        var an;
        
        if(nFrameMax && nFrame > nFrameMax) {stopped = 1; buttons();}
        if(gFrame && stopped != 1)
        	{
        	init(); // mtime(0)
        	nFrame++;
        	}
        
	if(gStyle == 2)
	{
        var bar = new RGraph.Bar('CDISP', ldata);

			    if(yMax != 0) bar.Set('chart.ymax', yMax);
		            bar.Set('chart.colors', [gColor]);
		            bar.Set('chart.gutter', gUtter);
		            bar.Set('chart.background.barcolor1', bColor);
		            bar.Set('chart.background.barcolor2', bColor);
		            if(xAxis )bar.Set('chart.xaxispos', 'center');
		            bar.Set('chart.yaxispos', 'left');
		            bar.Set('chart.ylabels', false); // see xTicks
		            bar.Set('chart.xticks',10);
		            bar.Set('chart.variant', gVariant);
		            if(gCross)
		            if(!document.all) bar.Set('chart.crosshairs',true);
		            bar.Set('chart.scale.decimals', 1);
					bar.Set('chart.background.grid.vsize',(lPos[1] - 2*gUtter)/100);
					bar.Set('chart.background.grid.hsize',(lPos[3] - 2*gUtter)/50);
					bar.Set('chart.title.vpos',5) ;
					bar.Set('chart.title',gTitle);

		            RGraph.Clear(cDisp); // speed it
		            bar.Draw();
		            gMax = bar.max;
		            display((nSteps*nMult)+nMin,adata[nSteps],bdata[nSteps]); // uses gMax
	} // BAR
	else
	{
            gLine = new RGraph.Line('CDISP',ldata,odata); // empty if plotting
            if(yMax != 0) gLine.Set('chart.ymax', yMax);
            
            gLine.Set('chart.ticksize',gTickSize);
            gLine.Set('chart.tickmarks.color',gTickColor);
	    gLine.Set('chart.tickmarks.dot.color',gTickColor);

            gLine.Set('chart.colors', [gColor,'blue']);
            gLine.Set('chart.tickmarks', gTick);
            gLine.Set('chart.linewidth', lWidth);
            gLine.Set('chart.background.barcolor1', bColor);
            gLine.Set('chart.background.barcolor2', bColor);

            if(yAxis) gLine.Set('chart.yaxispos','center'); // PATCH GB
            gLine.Set('chart.ylabels', false); // see xTicks
			gLine.Set('chart.xticks',10);
			if(gCross)
			if(!document.all) gLine.Set('chart.crosshairs',true);

            if (xAxis ) gLine.Set('chart.xaxispos', 'center');
            gLine.Set('chart.gutter',gUtter);
            gLine.Set('chart.background.grid.vsize',(lPos[1] - 2*gUtter)/100);
            gLine.Set('chart.background.grid.hsize',(lPos[3] - 2*gUtter)/50);

            if(gStepped) gLine.Set('chart.stepped', true); else gLine.Set('chart.stepped', false);
	    if(gFilled)  gLine.Set('chart.filled', true);  else gLine.Set('chart.filled', false)
	    gLine.Set('chart.fillstyle', [fColor,'blue']);
	    gLine.Set('chart.title.vpos',5) ;
	    gLine.Set('chart.title',gTitle);
	    if(wantsLine)
	    {
            RGraph.Clear(cDisp); // speed it
            gLine.Draw();
            }
            gMax = gLine.max;
            
            gLine.Set('chart.tickmarks', gMark);
            gLine.Set('chart.tickmarks.color',gMarkColor);
	    gLine.Set('chart.tickmarks.dot.color',gMarkColor);

            drawmarks();
            if(xMax == 0) xMax = yMax;
            drawgraph(xMax,yMax);
  	    
  	    display((nSteps*nMult)+nMin,adata[nSteps],bdata[nSteps]); // uses gMax
 
        } // style

	if(stopped == 1 || gError) return;
	
	if(gFrame)
	{
	if(stopped == 2) return;
	setTimeout(windraw, tInterval);
	return;
	}
	
	// scroll
	if(gReg) odata = null ;
	onMin += nMult ;
	nFrame++;
	// SHIFT  mark array made by drawmark()
	// SHIFT - use onSteps & onMin (no redef while scrolling)
	 for(i=0;i<onSteps;i++) adata[i] = adata[i+1] ;
	 for(i=0;i<onSteps;i++) ldata[i] = ldata[i+1];
	if(bScroll && odata) for(i=0;i<onSteps;i++) {bdata[i] = bdata[i+1] ;odata[i] = odata[i+1]}

	an = a((onSteps*nMult)+onMin)
	adata[onSteps] = an[0];
	ldata[onSteps] = scale(adata[onSteps]);
	if(ldata[onSteps] < 0) xAxis= 1;

	 if(bScroll && odata) 
		{
		bdata[onSteps] = an[1];
		odata[onSteps] = scale(bdata[onSteps]);
		}
		else bdata[onSteps] = undefined;

	
	tDisp2.innerText = tDisp2.textContent =  "a[" + format(onMin)  + "] = " + format(adata[0]) + '   nFrame = ' + nFrame;
	if(stopped == 2) return; // step by step

	setTimeout(windraw, tInterval);
	             
        } // windraw


/*------------------------------
paste
appends result to script
JavaScript format
------------------------------------*/
function paste(asel)
	{
	var i;
	var txt = document.forms.F.JEXPR.value ;
	if(txt == null) return;
	if(asel == 1 && odata == null) return;
	
	items = nSteps+1;
	
	// clear old /* ...*/
	if(asel == 0)
	{
	i = txt.indexOf ("\n/*---") ;
	if(i > 0 ) txt = txt.substring(0,i);
	}
	
	txt += "\n/*--- GBgraph " + gVersion;
	txt += "\ninterval(" +format(nMin) + ',' + format(nMin +nSteps*nMult) + ',' + nSteps + ');' ;
	if(asel == 0) txt += "\naList = [";
	if(asel == 1) txt += "\nbList = [";
		for(i=0; i< items ; i++)
		{
		if(i % 10 ==0) txt += '\n';
		if(asel == 0)
			{
			if(adata[i] == undefined) {txt +=' undefined'; break;}
			txt += '' + format(adata[i]);
			}
		if(asel == 1 && odata != null)
                        {
			if(bdata[i] == undefined) {txt +=' undefined'; break;}
			txt += '' + format(bdata[i]);
			}
		if(i < items-1 ) txt += ', ' ;
		}
	txt += "\n];"   ;
	txt += "\n---*/" ;
	document.forms.F.JEXPR.value= txt;
} // paste
	
/*------------------------------
npaste
appends result to script
JavaScript format [[n,a(n)] ,...]
------------------------------------*/
function npaste(asel)
	{
	var i;
	var txt = document.forms.F.JEXPR.value ;
	if(txt == null) return;
	if(asel == 1 && odata == null) return;
	
	items = nSteps+1;
	if(gList.length > 0) {items = gList.length ; asel =2;} // output gList (plotted)
	
	// clear old /* ...*/
	if(asel == 0 || asel == 2)
	{
	i = txt.indexOf ("\n/*---") ;
	if(i > 0 ) txt = txt.substring(0,i);
	}
	
	txt += "\n/*--- GBgraph " + gVersion;
	if(asel < 2)
	txt += "\ninterval(" +format(nMin) + ',' + format(nMin +nSteps*nMult) + ',' + nSteps + ');' ;
	else
	txt += "\nxMax = " + xMax + "; yMax = " + yMax +';'
	txt += "\nxAxis = " + xAxis + "; yAxis = " + yAxis +';'
	if(asel == 0) txt += "\ngList = [";
	if(asel == 1) txt += "\ngListB = [";
	if(asel == 2) txt += "\ngList = [";
		
		for(i=0; i< items ; i++)
		{
		if(i % 5 ==0) txt += '\n';
		if(asel == 2) // gList
			{
			txt += '[' + format(gList[i][0]) + ',' ;
			txt += '' + format(gList[i][1]) +']';
			}
		if(asel == 0) // a
			{
			txt += '[' + format(nMin+i*nMult) + ',' ;
			if(adata[i] == undefined) {txt +=' undefined]'; break;}
			txt += '' + format(adata[i]) +']';
			}
		if(asel == 1 && odata != null) // b
                        {
                        txt += '[' + format(nMin+i*nMult) + ',' ;
			if(bdata[i] == undefined) {txt +=' undefined]'; break;}
			txt += '' + format(bdata[i]) + ']' ;
			}
		if(i < items-1 ) txt += ', ' ;
		}
	txt += "\n];"   ;
	txt += "\n---*/" ;
	document.forms.F.JEXPR.value= txt;
} // npaste
	
	
/*-----------------------------
Select options
----------------------------*/
function makeselect()
{
var i;
document.forms.F.SCRIPT.options.length=0;
for(i=0;i<scriptDef.length;i++)
document.forms.F.SCRIPT.options[i] = new Option(scriptDef[i][0],"",false,false);
}

function doselect()
{
var selObj = document.getElementById('SCRIPT');
var selIndex = selObj.selectedIndex;
if(selIndex == 0) return;
if(scriptDef[selIndex][1] == '') return;
document.forms.F.JEXPR.value = scriptDef[selIndex][1] ;
reset(1);
newexpr();
draw();
}

/*--------------------------------
buttons()
---------------------------------------*/
function buttons()
{
document.forms.F.speedm.disabled = (stopped > 0);
document.forms.F.speedp.disabled = (stopped > 0);
document.forms.F.STOP.disabled = (stopped > 0) ;
document.forms.F.GO.disabled = (imageDone || gAnim == 0 || stopped == 0 || (nFrameMax && nFrame >= nFrameMax));
document.forms.F.SCRIPT.disabled = (stopped == 0);
document.forms.F.PASTE.disabled = (adata[0] == undefined);
document.forms.F.NPASTE.disabled = (adata[0] == undefined && gList.length < 1);
document.forms.F.STEP.disabled = (imageDone || gAnim == 0);
document.forms.F.IMG.disabled = (document.all || (stopped == 0));
}


////////////////////////////
/////// GUI - BUTTONS ACTIONS
//////////////////////

function trace(t)
{
mDisp.innerText = mDisp.textContent = '' + t ;
}

function draw()
{
reset(); // stopped= 1
init(); //  f(jExpr)
buttons();
windraw();
}

function animate()
{
if(gAnim == 0) {buttons();return;}
if(stopped == 0) return;
stopped=0;
buttons();
windraw(); // while(!stopped)  animate or scroll
} // go

function step()
{
if(gAnim == 0) {buttons();return;}
stopped=2; // in step
buttons();
windraw();
} // step

function stop()
{
stopped=1;
buttons();
} // stop


/*-------------------------------------
newexpr - 
a[n] -> an_
a[n-1] -> a(n-1)[0]
solve(a==b,..)--> zero(a-b,..,..)
----------------------------------------*/
function newexpr()
{
jExpr = document.forms.F.JEXPR.value;
stopped=1;


vExpr = jExpr.replace(/ *\]/g,']');
vExpr = vExpr.replace(/ *\[ */g,'[');
vExpr = vExpr.replace(/ *\)/g,')');
vExpr = vExpr.replace(/ *\( */g,'(');
vExpr = vExpr.replace(/a\[n\]/g,'an_');
vExpr = vExpr.replace(/b\[n\]/g,'bn_');
vExpr = vExpr.replace(/a\(n\)/g,'an_');
vExpr = vExpr.replace(/b\(n\)/g,'bn_');


vExpr = vExpr.replace(/a\(n((\+|\-|\*|\w)+)\)/g,'a(n$1)[0]');
vExpr = vExpr.replace(/a\[n((\+|\-|\*|\w)+)\]/g,'a(n$1)[0]');

vExpr = vExpr.replace(/b\(n((\+|\-|\*|\w)+)\)/g,'a(n$1)[1]');
vExpr = vExpr.replace(/b\[n((\+|\-|\*|\w)+)\]/g,'a(n$1)[1]');

vExpr = vExpr.replace(/zsolve\((.*) *== *(.*),(.*),(.*)\)/g,'_secant(function(n,an_){return(($1)-($2));},n,$3,$4)');
vExpr = vExpr.replace(/solve\((.*) *== *(.*),(.*),(.*)\)/g,'_zero(function(n,an_){return(($1)-($2));},n,$3,$4)');

//alert(vExpr);
}

/*-----------------------------
winload
---------------------------------*/
function winload()
{
newexpr();
draw(); // show example
}

window.onload = winload;


