/******************************************************************************
 *
 * Project:	Main Animator Javascript Class (used by PHP Console emulation  
 *		project).
 *
 * File:	animator.js
 *
 * Author:	Navaho Gunleg
 *		URL:    http://navahogunleg.net/phpstuff/console
 *
 * Created:	Sun Nov 27 15:58:58 CET 2005
 * 
 * History:	
 *   $Log$
 *
 *   0.1.0-20051127	Initial version.
 *
 ******************************************************************************
 * (c) Copyright Navaho Gunleg, 2005                      All Rights Reserved *
 ******************************************************************************
 $Id$
 */


/* NOTE:
 * p_text: Array( type, text )
 *	type 	0:	'Typing'
 *		1:	Slow display
 *		130:	Quick display + CR
 *		131	Quick display (no CR)
 *
 */
function animator( p_id, p_width, p_height, p_type, p_text, p_cols, p_rows )
{
	this.status = -1;

	// inherit parameters;
	this.width = p_width;
	this.height = p_height;
	this.text = p_text;
	this.type = p_type;
	this.fontSize = 12;

	this.line_index = 0;
	this.char_index = -1;

	this.done = 0;
	this.o = null;

	this.id = p_id;

	this.execute_timer = null;
	this.cursor_timer = null;

	this.init_text = null;
	this.init = 0;

	this.write_js = function( )
	{
		document.write( '<center><div class=\"console\" style=\"text-align: left;\" id=\"' + this.id + '\"></div></center>' );

	} // this.white_js( .. )

	this.increaseLine = function( )
	{
		this.current_line++;
		if (this.current_line == this.rows)
		{
			// Remove the first line:
			stop = 0;
			while ((o = this.o.firstChild) && (stop == 0))
			{
				if (o.nodeType == 1)
				{
					stop = 1;
				}

				this.o.removeChild( o );	
			}

			this.current_line--;
		}
	}

	this.kill = function( )
	{
		clearTimeout( this.execute_timer );
		clearTimeout( this.cursor_timer );
	}

	this.pause = function( )
	{
		this.kill( );
	}

	this.resume = function( )
	{
		this.execute_timer = setTimeout( this.id + '.execute( );', 500 );
		this.blink( );
	}

	this.setup = function( )
	{
		if ((this.o=document.getElementById( this.id )))
		{
			s = this.o.style;
			
			this.loop = 1;	// loop the animation
			this.zap = 0;	// when looping, reset contents or not

			switch (this.type)
			{
			  case 'c64':
				this.cursor_delay = 1000;
				this.cursor = '\u2588';

				this.cols = 40;
				this.rows = 16;

				if (p_cols != 0) this.cols = p_cols;
				if (p_rows != 0) this.rows = p_rows;
				this.current_line = 0;	
				this.fixed_delay = 1;

				this.init_text = Array( '    **** COMMODORE 64 BASIC V2 ****', 1,
							' 64K RAM SYSTEM  38911 BASIC BYTES FREE', 1,
							'READY.' );
				this.init_delay = 3500;

				s.width		= this.width;
				s.height	= this.height;

				s.background	= '#4d45d8;';
				s.color 	= '#a398ff;';
	
				// best font-size:
				i = (this.height / this.rows);
				j = (this.width / this.cols );
				size = j;
				//if (j < i) size = j;
				//else size = i;
				// about right
				this.width = ((size - 4) * this.cols);
				s.width	   = this.width;
		
				s.fontFamily = 'Courier New';
				s.fontSize   = size;
				s.fontWeight = 'bold';
		
				s.border	= (this.width / 10) + 'px solid #a398ff;'
				break;

			
			  case 'dos':
				this.cursor_delay = 250;
				this.cursor = '_';

				this.cols = 80;
				this.rows = 22;

				if (p_cols != 0) this.cols = p_cols;
				if (p_rows != 0) this.rows = p_rows;

				this.current_line = 0;
				this.fixed_delay = 1;

				this.prefix = '';
				this.init_text = Array( 'Microsoft(R) Windows 98',
						'  (C)Copyright Microsoft Corp 1981-1999.', 1,
						'C:\\> ', 0 );


				// best font-size:
				i = (this.height / this.rows);
				j = (this.width / this.cols );
				if (j < i) size = j;
				else size = i;
				

				s.width		= this.width;
				s.height	= this.height;

				s.borderTop	= '1px solid rgb(100,100,100);';
				s.borderLeft	= '1px solid rgb(100,100,100);';
				s.borderRight	= '1px solid rgb(100,100,100);';
				s.borderBottom	= '1px solid rgb(100,100,100);';
	
				s.background	= 'rgb(0,0,0);';
				s.color 	= 'rgb(255,255,255);';
	
				s.fontFamily = 'Lucida Console, Courier New';
				s.fontSize   =  size;

				s.border	= '1px solid rgb(100,100,100);';
				break;

			  case 'linux':

				this.cursor_delay = 250;
				this.cursor = '_';

				this.cols = 80;
				this.rows = 22;

				if (p_cols != 0) this.cols = p_cols;
				if (p_rows != 0) this.rows = p_rows;

				this.current_line = 0;
				this.fixed_delay = 1;

				this.prefix = '';
				this.init_text = Array( '', 1, '', 0 );

				// best font-size:
				i = (this.height / this.rows);
				j = (this.width / this.cols );
				if (j < i) size = j;
				else size = i;
				

				s.width		= this.width;
				s.height	= this.height;

				s.borderTop	= '1px solid rgb(100,100,100);';
				s.borderLeft	= '1px solid rgb(100,100,100);';
				s.borderRight	= '1px solid rgb(100,100,100);';
				s.borderBottom	= '1px solid rgb(100,100,100);';
	
				s.background	= 'rgb(0,0,0);';
				s.color 	= 'rgb(255,255,255);';
	
				s.fontFamily = 'Lucida Console, Courier New';
				s.fontSize   =  size;

				s.border	= '1px solid rgb(100,100,100);';
				break;

			  default:
				s.width		= '640;';
				s.height	= '400;';
				s.borderTop	= '1px solid rgb(100,100,100);';
				s.borderLeft	= '1px solid rgb(100,100,100);';
				s.borderRight	= '1px solid rgb(100,100,100);';
				s.borderBottom	= '1px solid rgb(100,100,100);';
	
				s.background	= 'rgb(0,0,0);';
				s.color 	= 'rgb(255,255,255);';
	
				s.fontFamily = 'Lucida Console, Courier New';
				s.fontSize   = this.fontSize + 'px;';

				break;

			} // switch
		
			this.current_cursor = this.cursor;
		}	
	}

	this.zap = function( ) 
	{
		// kill all the timers:	
		clearTimeout( this.cursor_timer );
		clearTimeout( this.execute_timer );

		// Remove everything from our assigned DIV:
		while(this.o.firstChild) this.o.removeChild( this.o.firstChild );

	}

	this.blink = function( )
	{
		this.removeCursor( );

		if (this.current_cursor == ' ') this.current_cursor = this.cursor;
		else this.current_cursor = ' ';

		this.appendCursor( );

		// Shoot off cursor-timer again:
		this.cursor_timer = setTimeout( this.id + '.blink( );', this.cursor_delay );
	}

	this.initialize = function( )
	{
		if ((this.init == 0) && (this.init_text))
		{
		
			for(i=0;i<this.init_text.length;i++) 
			{
				if (this.init_text[ i ] == 0) continue;

				iCr = 1;
				if ((i + 1 < this.init_text.length) && (this.init_text[ i + 1 ] == '0'))	
				{
					iCr = 0;
				}
				this.appendLine( this.init_text[i], iCr );
			}

			this.init = 1;
			this.appendCursor( );

			// Shoot off cursor-timer too:
			this.cursor_timer = setTimeout( this.id + '.blink( );', this.cursor_delay );
			return 1;
		}

		return 0;

	} // int init( )

	this.restart = function( )
	{
		if (this.zap == 1)
		{
			this.zap( );
	
			this.status = 0;
			this.init = 0;
			this.current_line = 0;
		}

		this.char_index = -1;
		this.line_index = 0;		

		if ((this.zap == 0) && (this.initialize( )) && (this.init_delay > 0))
		{
	    		this.execute_timer = setTimeout( this.id + '.execute( );', this.init_delay );
		}
		else
		{
			this.execute_timer = setTimeout( this.id + '.execute( );', 2500 );
		}

	}

	this.appendLine = function( a, b )
	{
		for(j=0;j < a.length;j++)
		{
			c = a[ j ];
			if (c == ' ') this.o.appendChild( document.createTextNode('\u00A0') );
			else this.o.appendChild( document.createTextNode( c ) );
		}

		if (b == 1) 
		{
			this.o.appendChild( document.createElement( 'br' ) );

			this.increaseLine( );
		}

	} // appendLine..

	this.appendCharacter = function( a )
	{
		this.removeCursor( );

		// Catch lines running of side of screen:
		if ( (this.char_index > 0) && (this.char_index % this.cols == 0) )
		{
			this.increaseLine( );

			this.o.appendChild( document.createElement( 'br' ) );
		}

		if (a == null) c = this.text[ this.line_index ][1][ this.char_index ];
		else c = a;

		if (c == ' ') this.o.appendChild( document.createTextNode('\u00A0') );
		else this.o.appendChild( document.createTextNode( c ) );

		this.appendCursor( );
	}

	// @removeCursor
	// --
	this.removeCursor = function( )
	{
		// remove cursor
		if ((z = document.getElementById( this.id + '_cursor' )) && (this.o) ) 
		{
			this.o.removeChild( z );
			return 1;
		}
		return 0; 
	}

	this.appendCursor = function( )
	{
		// remove cursor
		z = document.createElement( 'B' );
		z.id = this.id + '_cursor';
		z.appendChild( document.createTextNode( this.current_cursor ) );
		this.o.appendChild( z );
	}


	this.execute = function( ) 
	{
		iExtra = 0;
		iFixedTimeout = 0;


		switch(this.status)
		{
		  case 0:

			this.char_index++;

			if (this.line_index == this.text.length) 
			{
				this.done = 1;
				break;
			}

			if ( (this.text[ this.line_index ][ 0 ] == 130) ||
			     (this.text[ this.line_index ][ 0 ] == 131) 
			   )
			{
				this.removeCursor( );
				this.appendLine( this.text[ this.line_index ][ 1 ], (this.text[this.line_index][ 0 ] == 130?1:0) );
				this.appendCursor( );
				this.line_index++;
				this.char_index=-1;
				break;
			}

			if (this.char_index == this.text[ this.line_index ][1].length)
			{
				// Add newline to output:
				if (this.text[this.line_index][0] < 128) 
				{
					this.removeCursor( );
					this.o.appendChild( document.createElement( 'br' ) );
					this.increaseLine( );

					this.appendCursor( );
				}

				// Next line then, if there is:
				this.line_index ++;
				this.char_index = -1;

				if (this.line_index == this.text.length)
				{
					// finished...
					this.done = 1;	
				}

				iExtra = 1000;
				break;
			}

			c = this.text[ this.line_index ][1][ this.char_index ];
			if (this.o)
			{
				if ( ((this.text[ this.line_index][ 0 ] == 1)) ||
				     ((this.text[ this.line_index][ 0 ] == 129))
				   )
				{
					iFixedTimeout = this.fixed_delay; // 50;
				}

				this.appendCharacter( c );
			}

			break;

		  default:
		  case -1:
			// Test for our DIV, otherwise write in into the document;
			if (!(test=document.getElementById( this.id )))
			{
				this.write_js( );
			}
			this.setup( );
			this.status = 0;
			if (this.initialize( ) && (this.init_delay > 0))
			{
	    			this.execute_timer = setTimeout( this.id + '.execute( );', this.init_delay );
				return;
			}
		    	break;

		} // switch( ..

		if (this.done == 1)
		{
			if (this.loop == 1)
			{
				this.done = 0;
				this.restart( );
				// Return immediately not to shoot of too many timers:
				return;
			}
		}

		if (this.done == 0)
		{
		    	// Random timeout
			if (!(iTimeout = iFixedTimeout))
			{
				iTimeout =  iExtra + ( Math.random( ) * 400 ) + 100; // between 100 & 500
			}

		    	this.execute_timer = setTimeout( this.id + '.execute( );', iTimeout );
		}

	} // this.execute( .. )

	return this;
}

