/*array.js
//array manipulation functions
//see optimization used http://www.miislita.com/searchito/javascript-optimization.html
BS2008
BS2009
BS2010
USE AT YOUR OWN RISK
*/
Array.prototype.transpose=function(){
	    //all arrays must have equal length
	    var    a = this;	
	    var out = [];
	    var row = [];
	for(var k =0;k<a[0].length;k++)
	{    
	    for(var j=0; j < a.length;j++){
	        row.push(a[j][k]);
	    }
	    out.push(row);
	    row=[];
	}
	return out;
}



Array.prototype.spill = function(volLimit){
    //volLimit is max reservoir volume
    return this.map(function(x){
        return (x>volLimit)?(x-volLimit):0;
    })
}

Array.prototype.scale = function(scaleFactor){
    return this.map(function(x){return scaleFactor*x;})
}

Array.prototype.route=function(){
    var s = 0;
    var o = this.map(function(x){
        s+= x;
        s=(s<0)?0:s;
        return s;
    })
    return o;
}

Array.prototype.randompick=function()
{return a[Math.ceil(Math.random()*a.length)-1];}

Array.prototype.shuffle=function(o)
{
	//http://snippets.dzone.com/posts/show/849
        var o=this;
	for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
	return o;
}

Array.prototype.interpolate=function(x)
{
	 //interpolation of y at x WHERE x is not necessarily an integer
	 //Function used by scs_rainfall_oop.js
	 //and scs_rainfall.js
	 return this[Math.floor(x)]+(this[Math.ceil(x)]-this[Math.floor(x)])*(x-Math.floor(x));
}

Array.prototype.max = function(){
	return Math.max.apply({},this)
}
Array.prototype.min = function(){
	return Math.min.apply({},this)
}
Array.prototype.countzero=function(){
	var count=0;
	var k=this.length
	while(k){k--;
		if(this[k]==0){count++;}
	}
	return count;
}

Array.prototype.sum=function(){
    var k=this.length;
    var sum=0;
    while(k){k--;
        sum+=this[k];
    }
    return sum;
}


Array.prototype.mean=function(){
	return this.sum()/this.length;
}

function cumulative(A)
{	
	//example when A=[2,4,1,9] then return [2,6,7,16]
	var s = 0;
	return A.map(function(x){
		s+= x;
		return s;
	})
}

function add_first_k_elements(M,k)
{
	//add first k elements of the Martrix M
	var sum=0;
	for(var count=0;count<(k);count++)
	{sum=sum+M[count];}
	return sum;
}

function array_into_text(a)
{	//Returns the array data as a text column
	var msg=0;
	var n=a.length;
	for(count=0;count<n;count++)
	{	msg=msg+(count+1)+'\t\t'+((count+1)*5)+'\t\t'+(a[count]).toFixed(4)+'\n';}
	return msg;
}


Array.prototype.redistribute=function()
{	
	//Returns array Q
	//P must be pre-sorted to get meaningful output
	//The data is rearranged to form a Hyetograph
	//With Peak at the Middle
	//Other values will be thrown to the left and right of peak alternately

	var Q=new Array();
	var N=this.length;
	var mid=(N+(N%2))/2;
	var k=0;

	this.sort(numOrdD);
	Q[mid-1]=this[0];
	for(var k=2;k<=N;k++)
	{
		//var j=mid+Math.pow((-1),k)/2*(k-mod(k,2));
		var j=mid+Math.pow((-1),k)/2*(k-(k%2));
		Q[j-1]=this[k-1];
	}
	return Q;
}

Array.prototype.hyetograph=function(fraction)
{
	//redistribute the data to form a hyetograph with peak at the fraction time
	//usage A.hyetograph(0.25)
	var P=new Array();
	P=this.sort(numOrdD);
	var n=P.length;
	var peakPosition=fraction*n;	
	
	var P1=new Array(); //first portion
	var P2=new Array();	//second portion
	//slice P into two arrays
	if(fraction<=0.5)
	{
		P1=P.slice(0,peakPosition*2).redistribute();	//rearrange this portion of array
		P2=P.slice(peakPosition*2);	//no need to rearrange this portion
		return P1.concat(P2);
	}
	else
		{
			P1=P.slice(0,(n-peakPosition)*2).redistribute();
			P2=P.slice((n-peakPosition)*2);
	        		return (P2.reverse()).concat(P1);		
		}
}


Array.prototype.add=function(B)
{
    //console.log('algebrically adds two array\'s corresponding data value')
    var k=this.length-B.length;

	if(k!=0)
	{
	       if(k>0)
	       {    while(k){k--;B.push(0);}}
	    else
	    { k=-1*k;
	        while(k){k--;this.push(0);}
	    }
	}
    var C=[];
    var j=this.length;
    while(j){j--;C.push(this[j]+B[j]);}
    return C.reverse();
}


Array.prototype.makeTableTag=function()
{
	//returns table tag	
	var rmax=this.length;
	var k=rmax;
	var data;
        var cmax=0
	while(k){k--;
		if(this[k].length>cmax)
		{cmax=this[k].length;}
	}

	var tag=''

	for(var j=0;j<rmax;j++){
		var rowtag=''
		for(var k=0;k<cmax;k++)
		{
			data = this[j][k];
			//data = isNaN(data)?data:data.toFixed(1);
			//rowtag+='<td>' + data + '</td>';
			rowtag+='<td value=' + data + '>' + data + '</td>';
		}
		tag+= '<tr>' + rowtag + '</td>';
	}
	return '<table border=1 style={text-align:right}>'+tag+'</table>';
}


Array.prototype.toTable=function(row,col)
{
	//no jquery used
	//put this array starting at the cell (row,col)
	for(var k=0;k<this.length;k++){writeData(row+k-1,col-1,this[k]);}
}

Array.prototype.table=function(tableid,row,col)
{
    //put the array in table
    //start at cell of (row,col)
	//probably a slow method
    //needs jqtable.js
    for(var k=0;k<this.length;k++)
    {
        cell(tableid,row+k,col).text(this[k].toFixed(2));	//show it in cell
        cell(tableid,row+k,col).val(this[k]);	//write to value of cell
    }
}

Array.prototype.alert=function()
	{	//displays array content in alert box
		//usage like this A.alert()
		var msg="";
		for (var k=0;k<this.length;k++){msg=msg+'\n'+k+"  =>  "+this[k];}
		alert(msg);
	}

Array.prototype.write=function()
	{	//write array in the document
		//usage like this A.write()
		var msg="";
		for (var k=0;k<this.length;k++)
			{
				msg=msg+'\n'+k+"  =>  " + this[k]+"<br />";
			}
		document.write(msg);
	}

Array.prototype.max_consequtive_sum=function(n)
{
	//RETURNS AN ARRAY [startIndex,B] where B is array OF n CONSEQUTIVE ELEMENTS FROM THE ARRAY A WHICH HAS MAXIMUM SUM
	//alert("Running function max_consecutive_sum()...");
	n=parseInt(n);

	//n cannot be greater than the elements in the array
	if(n>this.length){n=this.length;}

	var k = 0;
	var i = 0;
	var max = 0; 
	var startPoint = 0;
	var N = this.length;
	for(var k=0; k<N-n+1; k++) 
	{
		var sum = 0;
		for(i=0; i<n; i++)
		{sum = sum + this[k+i];}
		if(sum > max)
		{
			max=sum;
			startPoint=k;
		}
	}

	//prepare new matrix to return
	var B=new Array();
	for(var m=0;m<n;m++){B[m]=this[startPoint+m];}

	return [startPoint,B];
}

Array.prototype.plot=function(divName,title,xscale,yscale)
{	//console.log("running Array.prototype.plot=function(divName,title,xscale,yscale)...");
	var g = new line_graph();

	//trying to set maximum as little above the highest value
	//var oldMax=max_value(this);	//disabled
	var oldMax=this.max();
	//console.log('oldMax = '+oldMax);
	var newMax=nextBigNumber(parseInt(oldMax));
	//console.log('newMax = ' + newMax);
	g.setMax(newMax);

	g.setScale(parseFloat(yscale));
	for (var k=0;k<this.length;k++)
	{
		//console.log(k+' : '+this[k]);
		g.add(k*xscale,this[k]*yscale);
	}
	g.render(divName, title,300);	//what is 300 for?
}

function nextBigNumber(x)
{
	//RETURNS A MULTIPLE OF 10, 100, 1000 ETC.
	//EXAMPLE nextBigNumber(745.87) RETURNS 1000
	//TO BE USED AS THE MAXIMUM Y AXIS VALUE WHILE PLOTTING
	var digits=String(x).length;
	var result="1";
	for(var i=0;i<digits;i++)
	{result=result+"0";}
	return parseFloat(result);
}

Array.prototype.gchart=function()
		{
			//gchart utilizes google chart api
			//basically, give data to google and get a png image back
			//9:35 PM 10/4/2008
			
			//Example usage:
			//var A=[100,2,4,8,16,32,64,50,40,30,20,10];
			//$('body').append(A.gchart())	//using jquery

			//alert('gchart()..\nNot Perfect');
			//console.log('gchart()..\nNot Perfect');
			var a='<img src="http://chart.apis.google.com/chart?cht=lxy&chs=300x225&chd=';

			//create x-data points
			//find max y value
			var max_y=Math.max.apply({},this);	//needed for scaling

			var b='t:';
			for(var k=0;k<this.length;k++)
			{	//x-axis
				if(k==this.length-1){var commaChar='';}
				else{var commaChar=',';}
				b=b+eval(k*10)+commaChar;
			}
			b=b+'|';
			for(var k=0;k<this.length;k++)
			{	//y-axis
				if(k==this.length-1){var commaChar='';}
				else{var commaChar=',';}

				b=b+this[k]*90/max_y+commaChar;
			}
			
			var c='&chco=3072F3,ff0000,00aaaa&chls=1,10,2&chg=20,50&chtt=Data|Sample+Only&chxt=x,t,y,r&chxr=2,0,100|1,0,100&chm=s,FF0000,0,-1,5|s,0000ff,1,-1,5|s,00aa00,2,-1,5" alt="gchart error"/>';

			var chartTag=a+b+c;
			//document.write('<fieldset>'+chartTag+'</fieldset>');
			return chartTag;

}
