//==========================================================================
//	Uguaglianza tra le proprietà numeriche di due oggetti (o tra numeri)

function decimali( n)			//	Number of significant decimals of a number
{
	var s,x;
	n = Math.abs( numero(n));
	s = n.toString();
	x = s.indexOf('.');
	if ( x < 0 ) x = s.indexOf(',');
	if ( x < 0 )
		x = 0;
	else	x = s.length - 1 - x;
	return x;
}
function uguali(o1,o2)
{
	var p, equal=false;
	if ( typeof(o1) == 'object' && typeof(o2) == 'object' )		//	Devono essere oggetti
	{
		if ( o1.constructor == o2.constructor )								//	Devono essere dello stesso tipo
		{
			equal=true;
			for ( p in o1 )											//	Verifica uguaglianza numerica
			{
//alert(typeof o1[p] + (o1[p] instanceof punto));
				if ( typeof(o1[p]) == 'number' && typeof(o2[p]) == 'number' )
					if ( Math.abs( o1[p] - o2[p] ) > 0.000001 )
						equal=false;
				if ( typeof(o1[p]) == 'string' && typeof(o2[p]) == 'string' )
					if ( ! ( o1[p] === o2[p] ) )
						equal=false;
				if ( typeof(o1[p]) == 'object' && typeof(o2[p]) == 'object' )
				{
					if ( ! uguali( o1[p], o2[p] ) )
						equal=false;
//alert(p+' '+equal);
				}
			}
		}
	}
	else
	{
		if ( isFinite(o1) && isFinite(o2) )								//	oppure numeri
			equal = ( Math.abs( o1 - o2 ) < 0.000001 );
		else
		if ( typeof(o1) == typeof(o2) )									//	o altro ?
		{
			equal = ( o1 == o2 );
		}
	}
	return equal;
}
//=============================================================================
//	Funzioni stringa
//
//	output		mette la stringa in una "div"
//	indexof		calcola n.a ricorrenza sottostringa
//	purge		toglie spazi non significativi
//	allNumeric	verifica se stringa totalmente numerica
//	padl			"padding" a sinistra, a destra, al centro
//	padr
//	padc
//	padL			"padding" con spazi HTML (&nbsp;)
//	padR
//	padC
//	stripTags		elimina tutti i "tag" da una stringa

function output(div)				//	Scrive la stringa "s" nella "div"
{								//	puo' essere il nome o l'oggetto
	var s = this.purge();
	if ( typeof(div) == 'string' )
	{
		if ( document.getElementById(div) != null )
			document.getElementById(div).innerHTML = s;
	}
	else
	if ( typeof(div) == 'object' && div['tagName']=='DIV' )	//   solo se "div"
	{
		if ( document.getElementById )	//	DOM
		{
			document.getElementById(div.id).innerHTML = s;
		}
		else							//	metodi obsoleti
		{
			if ( document.all )
				div.innerHTML = s;		//   Explorer
			else
			{
				div.document.write(s);	//	Netscape
				div.document.close();
			}
		}
	}
}
function indexof(sub,n,start)		//	Restituisce posizione n.a ricorrenza di "sub" in "s"
{
	var i,p,s;
	if ( arguments.length == 0 )
		p = 0;
	else
	{
		s = this;
		sub = stringa(sub);
		n = numero(n);
		start = numero(start);
		if ( n<=0 )
			p = -1;
		else
			for ( p=s.indexOf(sub,start), i=1; i<n && p>=0; i++ ) p = s.indexOf(sub,p+1);
	}
	return p;
}
function purge(c)					//	Toglie spazi non significativi (iniziali, finali, doppi)
{
	var i,s=this;
	if ( arguments.length == 0 ) c = ' ';
	c = stringa(c);
	if ( s.length > 0 )
	{
		while( s.charAt(0) == c )			s = s.slice(1);
		while( s.charAt( s.length-1) == c )	s = s.slice(0, s.length-1);
		while( ( i=s.indexOf(c+c) ) >= 0 )		s = s.slice(0,i) + s.slice(i+1);
	}
	return s;
}
function allNumeric()				//	Verifica se una stringa è totalmente numerica
{
	var i,lNumeric,s=this;
	for( i=0, lNumeric=true; i < s.length && lNumeric; i++)
		if( s.charAt(i) < '0' || s.charAt(i) > '9' ) lNumeric=false;
	return ( lNumeric && s.length > 0 );
}
function padding(n,c)				//	Costruzione parte mancante per il "padding"
{
	var pad='';
	n=numero(n);
	if ( this.length < n )
	{
		c = c ? c : ' ';
		c = stringa(c);
		while( pad.length < n ) pad+= c;
		pad = pad.slice(0,n-this.length);
	}
	return pad;
}
function padl(n,c)					//	"Padding" sulla sinistra
{
	return this.padding(n,c) + this;
}
function padr(n,c)					//	"Padding" sulla destra
{
	return this + this.padding(n,c);
}
function padc(n,c)					//	"Padding" al centro
{
	var r = Math.floor( ( n - this.length ) / 2);
	return ( this.padl( this.length + r, c) ).padr(n,c);
}
function padL(n)					//	"Padding" con spazi HTML
{
	var s = this.padl(n,String.fromCharCode(254));
	return s.replace(/[\u00FE]/g,'&nbsp;');
}
function padR(n)
{
	var s = this.padr(n,String.fromCharCode(254));
	return s.replace(/[\u00FE]/g,'&nbsp;');
}
function padC(n)
{
	var s = this.padc(n,String.fromCharCode(254));
	return s.replace(/[\u00FE]/g,'&nbsp;');
}
function stripTags()
{
	return this.replace( /(<([^>]+)>)/ig, '');
}
String.prototype.output=output			//	Prototipi
String.prototype.indexof=indexof
String.prototype.purge=purge
String.prototype.allNumeric=allNumeric
String.prototype.padding=padding
String.prototype.padl=padl
String.prototype.padr=padr
String.prototype.padc=padc
String.prototype.padL=padL
String.prototype.padR=padR
String.prototype.padC=padC
String.prototype.stripTags=stripTags

//=============================================================================
//	Funzioni per arrays (vettore-matrice)

Array.prototype.indexOf = function(x)		//	Ricerca
{
	var i, lTrovato = false;
	if ( typeof(x) != 'undefined' && this.length )
	{
		i = 0;
		while ( i < this.length && ! lTrovato )
		{
			if ( typeof( this[i] ) == typeof( x) )
				if ( uguali( this[i], x) )
					lTrovato = true;
//alert(i+' '+lTrovato+' '+this[i]+' '+x);
			if ( ! lTrovato ) i++;
		}
	}
	return lTrovato ? i : -1;
}
Array.prototype.normalizza = function()	//	Per polinomio: taglia gli zeri
{									//	dalle posizioni di grado più alto
	var nullo=true, n=Number.NEGATIVE_INFINITY;
	for( i=this.length-1; i>=0; i--)
	{
		if ( isFinite( this[i]) )
		{
			if ( this[i] != 0 ) nullo=false;
			if ( ! nullo && i > n ) n = i;
		}
	}
	if ( nullo ) n = 0;
	if ( isFinite(n) ) this.splice(n+1, this.length-n);
	return this;
}
Array.prototype.annulla = function()		//	Azzera
{
	var i;
	for( i=1; i<this.length; i++) this[i] = 0;
}
function vettore(n)
{
	var i;
	var a = new Array();

	if ( arguments.length >= 1 )
	{
		if ( typeof(n) == 'object' )
		{
			if ( n.length )
			{
				a.n = n.length;
				for (i=0; i<a.n; i++) a[i] = n[i];
			}
		}
		else
		if ( isVector(n) )
		{
			a.n = n.n;
			for (i=0; i<=a.n; i++) a[i] = n[i];
		}
		else
		if ( typeof n == 'string' )
		{
			if ( n.alltrim() == '' )
			{
				n = 0;
			}
			else
			{
				a = n.split(',');
				a.n = a.length - 1;
				for (i=0; i<=a.n; i++) a[i] = parseFloat( a[i]);
				a.reverse();
			}
		}
		else
		if ( n == undefined || n == null )
		{
			n = 0;
		}
	}
	if ( a.n == undefined )
	{
		if ( n == undefined ) n = 4;	//	lunghezza default
		n = numero(n);
		if ( n<=0 ) n = 0;
		a[0] = 0;					//	sentinelle
		if ( n>0 )
		{
			a[n+1] = 0;
			for (i=1; i<=n; i++)	//   valori
			{
				a[i] = Math.floor( Math.random() * 9 ) + 1;
			}
		}
		a.n = n;					//	lunghezza
	}
	a.vedi = vedivettore;			//	metodi per visualizzazione
	a.colonna = vedicolonna;
	a.poli = vedipolinomio;			//	Senza sentinelle
	a.scambio = _scambio;
//	a.poly = espressione;			//	Espressione algebrica del polinomio
//	a.derivata = deriva;			//	Funzione derivata
//	a.primitiva = integra;			//	Funzione primitiva
	return a;
}
//function espressione() { return this.polynomial(); } 
//function deriva() { return new vettore(this.funzionederivata()); }
//function integra() { return new vettore(this.funzioneprimitiva()); }

function matrice(m,n)
{
	var i,j, esempio1=false, esempio2=false;
	a = new Array();

	if ( arguments.length == 1 )
	{
		if ( typeof m == 'string' )
		{
			if ( m == 'esempio1' )
				esempio1=true;
			else
			if ( m == 'esempio2' )
				esempio2=true;
		}
		else
		if ( isMatrix(m) )
		{
			a.m = m.m;
			a.n = m.n;
			for (i=0; i<=m.m+1; i++)			//   Copia da matrice
			{
				a[i] = new Array();
				for (j=0; j<=m.n+1; j++) a[i][j] = m[i][j];
			}
		}
		else
		if ( isVector(m) )					//   Copia da vettore
		{
			a.m = 1;
			a.n = m.n;
			for (i=0; i<=a.m+1; i++)			//   Sentinelle
			{
				a[i] = new Array();
				for (j=0; j<=m.n+1; j++) a[i][j] = 0;
			}
			for (j=0; j<=m.n+1; j++) a[1][j] = m[j];
		}
	}
	if ( a.m == undefined || a.n == undefined )
	{
		if ( esempio1 )
		{
			m = 3;
			n = 4;
		}
		else
		if ( esempio2 )
		{
			m = 5;
			n = 6;
		}
		else
		{
			if ( m == undefined ) m = 4;	//   valori default
			if ( n == undefined ) n = m;
		}
		if ( m <= 1 || n <= 1 )
		{
			a[0] = new Array();
			a[0][0] = 0;
			m=n=0;
		}
		else
		{
			for (i=0; i<=m+1; i++)			//   sentinelle
			{
				a[i] = new Array();
				for (j=0; j<=n+1; j++) a[i][j] = 0;
			}
			if ( esempio1 )				//   valori per sistema lineare
			{
			/*
				 x - y +  z = 4		x = 2
				3x + y - 2z = 1		y = 1
				2x + y -  z = 2		z = 3
			*/            
				a[1][1] = 1;	a[1][2] = -1;	a[1][3] =  1;	a[1][4] = 4;
				a[2][1] = 3;	a[2][2] =  1;	a[2][3] = -2;	a[2][4] = 1;
				a[3][1] = 2;	a[3][2] =  1;	a[3][3] = -1;	a[3][4] = 2;
			}
			else
			if ( esempio2 )				//   valori per sistema lineare
			{
			/*
				 x + y +  z +  t +  u =  3		x =  1
				2x - y -  z + 2t - 6u = -6		y =  2
				 x + y -  z -  t - 2u =  2		z = -1
				5x - y                =  3		t =  0
				          z      + 5u =  4		u =  1
			*/            
				a[1][1] = 1;	a[1][2] =  1;	a[1][3] =  1;	a[1][4] =  1;	a[1][5] =  1;	a[1][6] =  3;
				a[2][1] = 2;	a[2][2] = -1;	a[2][3] = -1;	a[2][4] =  2;	a[2][5] = -6;	a[2][6] = -5;
				a[3][1] = 1;	a[3][2] =  1;	a[3][3] = -1;	a[3][4] = -1;	a[3][5] = -2;	a[3][6] =  2;
				a[4][1] = 5;	a[4][2] = -1;	a[4][3] =  0;	a[4][4] =  0;	a[4][5] =  0;	a[4][6] =  3;
				a[5][1] = 0;	a[5][2] =  0;	a[5][3] =  1;	a[5][4] =  0;	a[5][5] =  5;	a[5][6] =  4;
			}
			else
			for (i=1; i<=m; i++)		//   valori casuali
			{
				for (j=1; j<=n; j++) a[i][j] = Math.floor( Math.random() * 9 ) + 1;
			}
		}

		a.m = m;						//	righe
		a.n = n;						//	colonne
	}
	a.vedi = vedimatrice;			//	metodo per visualizzazione
	a.scambio = _scambio;
	a.annulla = _annulla;
	return a;
}
function _scambio(i1,j1,i2,j2)
{
	var x;
	if ( this.n == undefined ) return;
	if ( this.m == undefined )			//	Vettore (2 parametri)
		if ( arguments.length != 2 )
			return;
		else
		{
			i1 = numero(i1);
			j1 = numero(j1);
			if ( i1 >= 0 && i1 <= this.n+1 && j1 >= 0 && j1 <= this.n+1 )
			{
				x = this[i1];
				this[i1] = this[j1];
				this[j1] = x;
			}
		}
	else
		if ( arguments.length != 4 )		//	Matrice (4 parametri)
			return;
		else
		{
			i1 = numero(i1);
			j1 = numero(j1);
			i2 = numero(i2);
			j2 = numero(j2);
			if ( i1 >= 0 && i1 <= this.m+1 && j1 >= 0 && j1 <= this.n+1 &&
				i2 >= 0 && i2 <= this.m+1 && j2 >= 0 && j2 <= this.n+1 )
			{
				x = this[i1][j1];
				this[i1][j1] = this[i2][j2];
				this[i2][j2] = x;
			}
		}
}
function _annulla()				//	Azzera matrice
{
	var i,j;
	for( i=0; i<=this.m+1; i++)
		for( j=0; j<=this.n+1; j++)
			this[i][j] = 0;
}
function vedicolonna(div,sentinels)	//	Prepara tabella per visualizzazione vettore
{								//	in colonna (verticale)
	var i,j,n,s,z,Interi=true,pad;
	if ( this.n == undefined || arguments.length == 0 || arguments.length > 2 ) return;
	if ( arguments.length == 2 )
		if ( typeof(sentinels) != 'boolean' )
			sentinels = false;
		else;
	else	sentinels = true;

	n = this.n ? this.n + 1 : 0;
	for ( j=0; j<=n; j++)
		if ( decimali( Math.floor( this[j]*10000) / 10000 ) != 0 ) Interi = false;
	pad = Interi ? 4 : 5;
	s = '<table border=4 cellpadding=2>';
	for ( i=(sentinels?0:1); i<=(sentinels?n:n-1); i++)
	{
		s+= '<tr>';
		if ( i==0 || i==n )
			s+= '<td class=rosa>';
		else
			s+= '<td class=rossa>';
		s+= i.toString().padL(3) + '</td>';
/*		if ( Interi )
			z = isFinite( this[i]) ? this[i].toFixed(0).padL(4)+'&nbsp;' : '&nbsp;***&nbsp;';
		else
			z = isFinite( this[i]) ? this[i].toFixed(2).padL(7) : '&nbsp;******';
*/
		if ( i==0 || i==n )
			s+= '<td class=grigia>';
		else
			s+= '<td class=nera>';
		s+= printf(this[i],Interi) + '</td></tr>';
	}
	s+= '</table><br>';
	s.output(div);
	return s;
}
function vedivettore(div,sentinels)	//	Prepara tabella per visualizzazione vettore
{								//	normale (orizzontale)
	var i,j,n,s,z,Interi=true,pad;

	if ( this.n == undefined || arguments.length == 0 || arguments.length > 2 ) return;
	if ( arguments.length == 2 )
		if ( typeof(sentinels) != 'boolean' )
			sentinels = false;
		else;
	else	sentinels = true;

	n = this.n ? this.n + 1 : 0;
	for ( j=0; j<=n; j++) 
		if ( decimali( Math.floor( this[j]*10000) / 10000 ) != 0 ) Interi = false;
	pad = Interi ? 4 : 5;

	s = '<table border=4 cellpadding=2><tr>';
	for ( i=(sentinels?0:1); i<=(sentinels?n:n-1); i++)
	{
		if ( i==0 || i==n )
			s+= '<td class=rosa>';
		else
			s+= '<td class=rossa>';
		s+= i.toString().padL(pad) + '</td>';
	}
	s+= '</tr>';
	for ( i=(sentinels?0:1); i<=(sentinels?n:n-1); i++)
	{
/*		if ( Interi )
			z = isFinite( this[i]) ? this[i].toFixed(0).padL(4)+'&nbsp;' : '&nbsp;***&nbsp;';
		else
			z = isFinite( this[i]) ? this[i].toFixed(2).padL(7) : '&nbsp;******';
*/		if ( i==0 || i==n )
			s+= '<td class=grigia>';
		else
			s+= '<td class=nera>';
		s+= printf(this[i],Interi) + '</td>';
	}
	s+= '</tr></table><br>';
	s.output(div);
	return s;
}
function vedipolinomio(div)	//	Prepara tabella per visualizzazione vettore
{						//	contenente coefficienti di un polinomio
	var i,j,n,s,z,Interi=true,pad;
	if ( this.n == undefined || arguments.length != 1 ) return;

	n = this.n ? this.n + 1 : 0;
	for ( j=0; j<=n; j++) 
		if ( decimali( Math.floor( this[j]*10000) / 10000 ) != 0 ) Interi = false;
	pad = Interi ? 4 : 5;
	s = '<table border=4 cellpadding=2><tr>';
	for ( i=n; i>=0; i--) s+= '<td class=rossa>' + i.toString().padL(pad) + '</td>';
	s+= '</tr>';
	for ( i=n; i>=0; i--)
	{
/*		if ( Interi )
			z = isFinite( this[i]) ? this[i].toFixed(0).padL(4)+'&nbsp;' : '&nbsp;***&nbsp;';
		else
			z = isFinite( this[i]) ? this[i].toFixed(2).padL(7) : '&nbsp;******';
*/		s+= '<td class=nera>' + printf(this[i],Interi) + '</td>';
	}
	s+= '</tr></table><br>';
	s.output(div);
	return s;
}
function vedimatrice(div,sentinels)	//	Prepara tabella per visualizzazione matrice
{
	var i,j,m,n,s,z,Interi=true,pad;
	if ( this.n == undefined || arguments.length == 0 || arguments.length > 2 ) return;
	if ( arguments.length == 2 )
		if ( typeof(sentinels) != 'boolean' )
			sentinels = false;
		else;
	else	sentinels = true;
	m = this.m ? this.m + 1 : 0;
	n = this.n ? this.n + 1 : 0;
	if ( m<=1 || n <= 1 ) sentinels=true;
	for ( i=0; i<=m; i++)
		for ( j=0; j<=n; j++) 
			if ( decimali( Math.floor( this[i][j]*10000) / 10000 ) != 0 ) Interi = false;
	pad = Interi ? 4 : 5;
	s = '<table border=4 cellpadding=2><tr>';
	s+= '<td class=rosa>&nbsp;&nbsp;&nbsp;</td>';
	if ( sentinels )
	{
		s+= '<td class=rosa>' + (0).toString().padL(pad) + '</td>';
	}
	for ( i=1; i<=this.n; i++) s+= '<td class=rossa>' + i.toString().padL(pad) + '</td>';
	if ( sentinels && this.n > 0 )
	{
		s+= '<td class=rosa>' + (this.n+1).toString().padL(pad) + '</td>';
	}
	s+= '</tr>';
	for ( i=(sentinels?0:1); i<=(sentinels?m:m-1); i++)
	{
		if ( i==0 || i==m )
			s+= '<tr><td class=rosa>';
		else
			s+= '<tr><td class=rossa>';
		s+= i.toString().padL(3) + '</td>';
		for ( j=(sentinels?0:1); j<=(sentinels?n:n-1); j++)
		{
/*			if ( Interi )
				z = isFinite( this[i][j]) ? this[i][j].toFixed(0).padL(4)+'&nbsp;' : '&nbsp;***&nbsp;';
			else
				z = isFinite( this[i][j]) ? this[i][j].toFixed(2).padL(7) : '&nbsp;******';
*/			if ( i==0 || i==m || j == 0 || j==n )
				s+= '<td class=grigia>';
			else
				s+= '<td class=nera>';
			s+= printf(this[i][j],Interi) + '</td>';
		}
		s+= '</tr>';
	}
	s+= '</table><br>';
	s.output(div);
	return s;
}
function printf( x, Interi)
{
	var z;
	if ( Interi )
		z = isFinite( x) ? x.toFixed(0).padL(4)+'&nbsp;' : '&nbsp;***&nbsp;';
	else
		z = isFinite( x) ? x.toFixed(2).padL(7) : '&nbsp;******';
	return z;
}
function innerVector(v)				//	Vettore privato delle sentinelle
{
	if (isVector(v))
		return v.slice(1,-1);		//	serve un costruttore da "isVector"
	else	return null;
}
function len(a,n)					//	Lunghezza
{
	if ( typeof(a) == 'object' )
		if ( typeof(a[0]) == 'object' )
		{
			if ( n == undefined || ! isFinite(n) )
				return ( a.length - 2 ) * ( a[0].length - 2 );
			else if ( n == 1 )
				return a.length - 2;
			else if ( n == 2 )
				return a[0].length - 2;
		}
		else
			return a.length - 2;
	return -1;
}
function isVector(a)				//	Verifica se è un vettore
{
	if (a)
		return ( a.n != undefined && a.m == undefined );
	else	return false;
}
function isMatrix(a)				//	Verifica se è una matrice
{
	if (a)
		return ( a.m != undefined && a.n != undefined );
	else	return false;
}

//=============================================================================
// Funzioni di varia utilità
//

function ListObj(obj) 				//	Dump
{
	var s = new Array ();
	var o;
	var j = 0;
	for (o in obj) s[j++] = o + ': ' + obj[o];
	return s.sort().join('<br>');
}
function collection(o)				//	Dump
{
	var s=new Array(),x,j=0;
	if ( typeof(o)=='object' )
		if ( o.length )
		{
			for(x=0; x<o.length; x++) s[x]=o[x];	//	"arguments"
		}
		else
		{
			for(x in o) s[j++]=x;					//	altri oggetti
		}
	s.sort();
	return s.toString();
}
function stringa(s)				//	Assicura che "s" sia una stringa
{
	if ( typeof(s) != 'string' ) s = s + '';
	return s;
}
function contiene(div,s)			//	Mette la stringa nella div
{								//	(commutativa: div-stringa/stringa-div) 
	if ( document.getElementById(div) )
	{
		s = stringa(s);
		if ( document.getElementById(div).canHaveHTML )
			document.getElementById(div).innerHTML = s;
	}
	else
		contiene(s,div);
}
function random(n)					//	"random" intero (0..n)
{
	n = numero(n);
	return Math.floor( Math.random() * n);
}

function valore(box)				//	Valore di una BOX purgato
{
	var x = '';
	if ( box ) if ( box.tagName == 'INPUT' ) x = box.value;
	return x.purge();
}
Math.logb = function(x,b)			//	Logaritmo in base qualunque
{
	return Math.log(x) / Math.log(b);
}
function numero( n)				//	Restituisce comunque un numero
{
	if ( typeof(n) == 'undefined' ) n = 0;
	if ( typeof(n) == 'string' ) n = parseFloat(n);
	if ( typeof(n) != 'number' ) n = 0;
	return n;
}
function RadioValue( radio)			//	Parametro: "name" o "id"
{								//	In FireFox accetta solo "name"
	var collection, n, i;
	collection = document.all(radio);
	for (n=-1, i=0; i<collection.length && n<0; i++) if (collection[i].checked) n=i;
    return n;
}
function sleep(msec)				//	attende (millisecondi)
{								//	N.B.: inutile
	var d = new Date();
	var t1 = d.getTime();
	var t2 = t1 + numero(msec);
	if( t2 < t1 )
	{
		t1 = 0;
		//t2+= differenza tra mezzanotte e t1
	}
	while( t1 < t2 )
	{
		d = new Date();
		t1 = d.getTime();
	}
	return t2;
}

