var NGcontainer="container"  //main div tag holding everything else..

//debug variables
var CurFunc;
var dbgThread;
var showConsole=false;

//innerHTML	variables
var _NSBuffer=new Array;
var _NSObjs=new Array;
var __bufferfunc="";

//div caching variables
var enablecache=false;
var cachesize=0;
var divLabels=new Array(cachesize);
var divObjs=new Array(cachesize);

//keyboard access variables
var __keybuffersize=5;
var keybuffer=new Array(false,false,false,false);
var codebuffer=new Array(false,false,false,false);
var keyind=0;

//thread variables
var functions = new Array();
var _threads=0;
var _threadtimers=new Array();
var funcNo=new Array();

//auto render variables
var _renderFunc="";
var _renderSkip="";
var _maxSkip=0;
var _renderFrame=0;
var _frameCount=0;
var _irq="";

//div dragging variables 
var __moving=false; 
var _NSDIV="";
var _x,_y,_tempx,_tempy;
var _draggable=new Array();
var _dragtotal=0;
var _setvirtual=false;
var _vx,_vy,_vc;
var objsX=new Array()
var objsY=new Array()
var objsCount=0; 
var _disableNSRefresh=false;
var mouseup=true;
var _NStmp="";

//fading variables
var user_thread=false;
var errorlog="";
var _disableMozTrans=true;
var fdIN=15;
var fdOUT=6;

//Extensions
var EXTfade=true;	          //fade objects in and out smoothly..
var EXTfastdrag=true;		  //drag only window borders, not window contents
var EXTfastexe=false;

var progID="ngine v1.0, Robert Gamble\n"
rVal=4;


//debug functions
function allowDebugging()
{
  dbgThread=_createThread(1);
  document.all["_console"].value=progID;
 _initKeys();

  addFunction(dbgThread,"_ngineDebug()");
  _makeDraggable("ngineconsole")
}

function _ngineDebug()
{
	if(showConsole==false)
	{
		if(keyinput("p")){
		showConsole=true;
		_divVis("ngineconsole","show");
		}
	}

}

function show_errors()
{
	document.all["_console"].value+="errors: \n"+errorlog+"\n";
}

function show_keys()
{
	tmpKeys=0;
		document.all["_console"].value+="Keyboard buffer contents:\n"
		while (tmpKeys<__keybuffersize)
		{
			document.all["_console"].value+=keybuffer[tmpKeys]+",";
			tmpKeys++;
		}

		document.all["_console"].value+="\n";
}

function show_threads()
{
	tmpThread=1
		while (tmpThread<=_threads)
		{
		   tmpFunc=1;
		   document.all["_console"].value+="Processes in thread: "+tmpThread +"\n";
		   while	 (tmpFunc<=funcNo[tmpThread]+1)
			{
			   document.all["_console"].value+=functions[tmpThread][funcNo[tmpFunc]]+"\n";
			   tmpFunc++;
			}
		 tmpThread++;
		}
}
function hide_console()
{
	showConsole=false
	_divVis("ngineconsole","hide")
}

function sendComm()
{
	tmp=document.all["comms"].value;


	try{
		document.all["_console"].value+=tmp +"\n";
	eval(tmp);
	
	}
	catch(error){
		
		errorlog+="unknown function or command\n";
		}
	 

	document.all["comms"].value="";
}


//innerHTML functions

function _setBufferFunc(func)
{
  CurFunc="_setBufferFunc("+func+")";

  __bufferfunc=func;	 
}

function _innerHTML(tag,text,append)
{
  CurFunc="_innerHTML("+tag+","+text+","+append+")";

  var chrk=(append=="no")?"=":"+=";
  if(!document.all && __bufferfunc!="")eval(__bufferfunc + "('read')");
	if (document.layers)
	{
		if(append=="yes")eval("_NSBuffer" + chrk + "text");

		_Sx = _div(tag);		
		with(_Sx)
		{
		  document.open();
		  (append=="yes")?document.writeln("<p>"+_NSBuffer+"</p>"):document.writeln("<p>"+text+"</p>");
	 	  document.close();		 
		  if(_setvirtual==true)_NSdivrender("all");
		}
	}

  if(document.all)eval("document.all." + tag + ".innerHTML" + chrk + "text");	  
  else if(document.getElementById)eval("document.getElementById(tag).innerHTML" + chrk + "text");
  if(!document.all && __bufferfunc!="")eval(__bufferfunc + "('write')");
}

//div caching..  puts div objects into memory, more (alot) speed but more ram usage

function _setDivCache(csize)
{
  CurFunc="_setDivCache("+csize+")";

  cachesize=csize;
  enablecache=true;
}

//api called function.  This is used to fetch objects from the cache
function _divCache(name)
{
  CurFunc="_divCache("+name+")";

  var e=cachesize;
   do
	{
	  if(divLabels[e]==name)return divObjs[e];	  
	  e--;
	}while(e>=0)
  return false;
}

//api called function.  Used to add stuff into the cache
function _addToCache(name,obj)
{
  CurFunc="_divCache("+name+")";

  var e=cachesize;
  do
	{
	  divLabels[e]=divLabels[e-1];
	  divObjs[e]=divObjs[e-1];

	  e--;
	} while(e>=0)

	divLabels[0]=name;
	divObjs[0]=obj;
}


//dimension functions.  Get the dimensions of the document or objects on the document.

function _getDocSize(dim)
{
  CurFunc="_getDocSize("+dim+")";

  if(dim=="w" || dim=="x")
    {
	 tmp= (document.all)?window.top.document.body.clientWidth:window.innerWidth;
	}

  if(dim=="h" || dim=="y")
    {
	 tmp= (document.all)?window.top.document.body.clientHeight:window.innerHeight; 
	}

	return tmp;
}


//user called function.  Returns the height of "object".
function _getHeight(object)
{
 CurFunc="_getDocSize("+object+")";

 var _h;
 if(document.layers)_h=eval(_div(object).document.height);
 if(document.all)_h=document.all[object].offsetHeight;
 if(document.getElementById)_h=document.getElementById(object).offsetHeight;

 if(_h==0)_h=20;
 return _h;
}

//user called function.  Returns the width of "object"
function _getWidth(object)
{
 CurFunc="_getDocSize("+object+")";

 var _h;
 if(document.layers)_h=eval(_div(object).document.width);
 if(document.all)_h=document.all[object].offsetWidth;
 if(document.getElementById)_h=document.getElementById(object).offsetWidth;

 if(_h==0)_h=20;
 return _h;
}

//hide/show objects
function _divVis(object,status)
{
  CurFunc="_getDocSize("+object+","+status+")";

  var sf;
  if(EXTfade==true && object!=NGcontainer && object!="fstdrg")
	{
	  status=(status=="show" || status=="visible")?1:0;

	  setFade(object,status);
	}
  else{
  
  if(object!=NGcontainer)
	  {
  if(document.all[object].filters.alpha)document.all[object].filters.alpha.opacity=100;
  else if(document.getElementById && _disableMozTrans==false)document.getElementById(object).style.Opacity=100;
	  }
  if(status=="visible" || status=="show")sf=(document.layers)?"show":"visible";
  if(status=="hidden" || status=="hide")sf=(document.layers)?"hide":"hidden";

  _div(object).visibility=sf;

  return sf;
	}
}




//movement routines

//user called function.  returns the x or y coordinate of a div tag, _getpos("div2","y") returns the "top" property of div2
function _getpos(object,xy)
{
  CurFunc="_getpos("+object+","+xy+")";

  var temp;
  //get the coordinates
  temp=(xy=="x")?_div(object).left:_div(object).top;
  
  //return value
  //i.e returns "(number)px", so that has to be ripped out first..
  if(!document.layers)return (temp.substring(temp.length-2,temp.length)=="px")?parseInt(temp.substring(temp,temp.length-2)):temp;
  else return temp;
}

//move stuff easily

//user called function.  Moves "object" to nx,ny


function _move(object,nx,ny)
{
  CurFunc="_move("+object+","+nx+","+ny+")";

  //yeah!
  with(_div(object))
	{
    left=nx;
    top=ny;
	}
}


//object functions.  

//api called function returns a div tag object..  
//either by looking at the document object, or reading/writing to the cache
function _div(name)
{
   CurFunc="_div("+name+")";

   var temp=(enablecache==true)?_divCache(name):temp=false;

   if(temp==false)
	{
     temp=(document.all)?eval("document.all." + name + ".style"):_getLayer(document,name);
	 
	 if(enablecache==true)_addToCache(name,temp);
	}
   
   return temp;	 
}

//extract layers for netscape..
function _getLayer(obj,name)
{
	CurFunc="_getLayer("+obj+","+name+")";

	if(document.getElementById)
	{
		return document.getElementById(name).style;
	}
	else
	{
	var x = obj.layers;
	var thereturn;
	for (var i=0;i<x.length;i++)
	{
		if (x[i].id == name)
		 	thereturn = x[i];
		else if (x[i].layers.length)
			var tmp = _getLayer(x[i],name);
		if (tmp) thereturn = tmp;
	}
	return thereturn;
	}
}


//The keyboard handling routines
//this is really insane crap..
//Javascript and stuff is supposed to simplify stuff and be all high-level
//so how come I have to write all this crap to read more than one keypress at a time?

//user called function.  Call this function if you want to be able to use the keyboard.
function _initKeys()
{
  CurFunc="_initKeys()";

  if (!document.all)document.captureEvents(Event.KEYPRESS|Event.KEYUP);
  
  //set functions that handle keys..
  document.onkeypress = key;	                
  document.onkeyup= clearKeyBuffer;
}
var lstKey="";


//api called function..  Reads keypresses and stores them in the keybuffer
function key(e)
{
  CurFunc="_key("+e+")";	
 code = (!document.all)? e.which : event.keyCode;

  key = String.fromCharCode(code).toLowerCase();

  var temp=__keybuffersize;
  var ret=false;

  if(!keyinput(key))
    {
    while(temp>=1)
      {
	  codebuffer[temp]=codebuffer[temp-1];
      keybuffer[temp]=keybuffer[temp-1];
  	  temp--;
	}
	keybuffer[0]=key; 
	codebuffer[0]=code;
  }

}

//user called function.  Checks if a key is being pressed..  I.e if "a" is being pressed keyinput("a") will return true.  Otherwise it'll return false
function keyinput(key,retw)
{
  CurFunc="keyinput("+key+")";

  var i=0;
  var ret=false;
  while(i<=__keybuffersize)	//read through the key buffer
    {
	   if(keybuffer[i]==key)return true;
	   i++;
	}

  return (retw==true)?keybuffer[i]:false;
}

//api called function.  Deletes items from the keybuffer
function clearKeyBuffer(e)
{
  CurFunc="clearKeyBuffer("+e+")";

  code = (!document.all)? e.which : event.keyCode;
  key = String.fromCharCode(code).toLowerCase();
  
  var temp=0;
  while(temp<=__keybuffersize)
  {
    if(keybuffer[temp]==key)keybuffer[temp]="";
  	temp++;
	}
	codebuffer[0]=false;
}


//some wierd engine shit crap bollocks..
//hello my name is daniel johns.
//i am in a band called silverchair
//we suck

//this stuff should probably all have underscores before stuff but I can't be botheredddddddd

//set the function list array and create an index

function _createThread(rate)
{
  CurFunc="_createThread("+rate+")";

  _threads++;
  functions[_threads]=new Array();
  funcNo[_threads]=-1;
  main(_threads,rate);
  user_thread=1;
  
  return _threads;
}



//user called function.  Adds a function call to the program.
function addFunction(thread,func)
{
  CurFunc="addFunction("+thread+","+func+")";
  if(checkFunction(thread,func)==false)	//make sure the function doesn't exist in the function list already..
  {

    funcNo[thread]++;	   //increment the index
	functions[thread][funcNo[thread]]=func;					 //add the function
	}
}

//api called function. checks to see if a function exists in the function list.
function checkFunction(thread,func) 
{
  CurFunc="checkFunction("+thread+","+func+")";
  var i=0;
  var found=false;
  //where abouts in the array is "func"?
  while(i<=funcNo[thread])
    {
	 if(functions[thread][i]==func)found=i;
	 i++;
  } 

  return found;	 //return false if "func" wasn't found otherwise return its place in the function list..
}

//user called function.  Deletes a function call from the program.
function deleteFunction(thread,func)
{
  CurFunc="deleteFunction("+thread+","+func+")";
  var i=checkFunction(thread,func);		//get "func"s place in the function list
  //alert(i + " "+ func);
  //shift everything down..
  if(i>=0 && i!=false)				 
    {

	  functions[thread][i]="";
     while(i<=funcNo[thread])
       {
	    functions[thread][i]=(functions[thread][i+1]!="")?functions[thread][i+1]:"";
	    i++;
     } 
	   funcNo[thread]--;				 //decrement the index
  }
}



//user called function.  _setRenderer(the name of the renderering function (string),frameskip (integer),automatically calculate frameskip ("yes" or "no"))
//setting auto to "yes", may  increase cpu usage..  But it will  make sure that everything runs at a constant speed..
function _setRenderer(func,skip,auto,max)
{
  CurFunc="_setRenderer("+func+","+skip+","+auto+","+max+")";
  _renderFunc=func;
  _renderSkip=skip;
  _maxSkip=max;
  if(auto=="yes")_chkSkip();

  _autoRender();
}

//api called function.  Calculates the frameskip
function _chkSkip()
{
  CurFunc="_chkSkip()";
  if	 (_frameCount<45 && _renderSkip<_maxSkip)_renderSkip++;
  if (_frameCount>50 && _renderSkip>0)_renderSkip--;
  _frameCount=0;

  _irq=setTimeout("_chkSkip()",500);
}

//user called function.  rte=rate in miliseconds..  debug= path of a textbox/input box to write debug info into//
function main(thread,rate)
{
 CurFunc="main("+thread+","+rate+")";

 var i=funcNo[thread];

 if(EXTfastexe)
	{
 var n=i/rVal;
 var tst=i%rVal;

 do
   {
	 switch(tst)
	   {
	   case 0: eval(functions[thread][tst]);
	   case 1: eval(functions[thread][tst]);
	   case 2: eval(functions[thread][tst]);
	   case 3: eval(functions[thread][tst]);
	   case 4: eval(functions[thread][tst]);
	   case 5: eval(functions[thread][tst]);
	   case 6: eval(functions[thread][tst]);
	   case 7: eval(functions[thread][tst]);
	   }
	   tst=0;
	}while(--n>=0)
	}
 else{
 do{
 eval(functions[thread][i]);
 i--;
 }while(i>=0)
 }

 var temp=setTimeout("main(" + thread + "," + rate+")",rate)
}

function _autoRender()
{
   CurFunc="_autoRender()";

	_renderFrame++;
	if(_renderFrame>=_renderSkip)
	{
		_renderFrame=-1;
		
		eval(_renderFunc);

	}
	_frameCount++;

	var _aut=setTimeout("_autoRender()",1)
}

//user called function compare coordinates...
function _colDetect(obj1,x,y,obj2)
{
  CurFunc="_colDetect("+obj1+","+x+","+y+","+obj2+")";
  if(x=="na" || y=="na")
	{
	  x=_getpos(obj1,"x");
	  y=_getpos(obj1,"y");
	}
  
  var y2=_getpos(obj2,"y");
  
  if((_getHeight(obj1)+y)>=y2 && y<(_getHeight(obj2)+y2))
	{
	  var x2=_getpos(obj2,"x");
	  if(x+_getWidth(obj1)>=x2) 
		{
		  if((x<=x2+_getWidth(obj2)))return true;
		}
	}
  return false;
}

//user called..  compares object to points
function _colDetectPoints(obj,x,y)
{
  CurFunc="_colDetectPoints("+obj+","+x+","+y+")";

  if(x>=_getpos(obj,"x") && x<=	(_getpos(obj,"x")+_getWidth(obj)) && y>=_getpos(obj,"y") && y<=_getpos(obj,"y")+_getHeight(obj))return true;
  else return false;
}


//div dragging..

function startdrag(e) 
{	 
  CurFunc="startdrag("+e+")";
  var _o=0;
  mouseup=false;


  _tempx=_getMousePos(e,"x")
  _tempy=_getMousePos(e,"y")
  _NSDIV=false;


  
  while(_o<_dragtotal)
     {
	  if(_div(_draggable[_o]).zIndex-1>=0)_div(_draggable[_o]).zIndex-=1;
      if(_colDetectPoints(_draggable[_o],_tempx,_tempy) && _div(_draggable[_o]).visibility!="hidden")
		 {
		  try{centered[_o]="";}
		  catch(e){}
		  _NSDIV=_draggable[_o];
		  _div(_NSDIV).zIndex=10;
		  _vc=_o;
		
		 }
      _o++;
      }

  if(_NSDIV!=false)
  {
  _x=_getpos(_NSDIV,"x");
  _y=_getpos(_NSDIV,"y");

 __moving=true;
 
 if(EXTfastdrag==true &&  _NSDIV.substr(0,6)!="imgdrg")
	  {
	  
	   _NStmp=_NSDIV;
	   _NSDIV="fstdrg	";

	   _innerHTML(_NSDIV,"<table width=" + _getWidth(_NStmp) + " height=" + _getHeight(_NStmp) + " border=1><tr><td>&nbsp</td></tr></table>","no");
	   _move(_NSDIV,_getpos(_NStmp,"x"),_getpos(_NStmp,"y"));
	   _divVis("fstdrg","show");
	  }
 //alert(_NSDIV+" " + _NStmp);
 if(document.layers)document.captureEvents(Event.MOUSEMOVE);
 document.onmousemove=move;
 }

 return false;
}


_Mfsk=0;
_mfsc=0;
function move(e)
{	
  CurFunc="move("+e+")";

  if(_mfsc>_Mfsk)
	{
  if(__moving==true && _setvirtual==false)_move(_NSDIV,_x+_getMousePos(e,"x")-_tempx,_y+_getMousePos(e,"y")-_tempy)
  if(__moving==true && _setvirtual==true)
	{
	  objsX[_vc]=_x+_getMousePos(e,"x")-_tempx;
	  objsY[_vc]=_y+_getMousePos(e,"y")-_tempy;
	  _NSdivrender(_vc);
	}
	_mfsc=0;
	}
	else _mfsc++;
   return false;
  }


function _getMousePos(e,coord)
{
  CurFunc="_getMousePos("+e+","+coord+")";
  
  if(document.layers)return (coord=="y")?e.pageY +window.scrollY:e.pageX +window.scrollX;
  if(document.all)return (coord=="y")?event.clientY+ document.body.scrollTop:event.clientX+ document.body.scrollLeft;
  if(document.getElementById)return (coord=="y")?e.clientY+ window.scrollY:e.clientX+ window.scrollX
}

var _mDRGEN=false;
function _makeDraggable(divid)
{
  CurFunc="_makeDraggable("+divid+")";
  if(document.layers && _setvirtual==false)_setNSRefresh();
  if(_div(divid).cursor!="move")_div(divid).cursor="hand";
  _draggable[_dragtotal]=divid;
  objsX[_dragtotal]=(_getpos(divid,"x")=="")?0:_getpos(divid,"x");
  objsY[_dragtotal]=(_getpos(divid,"y")=="")?0:_getpos(divid,"y");
  _dragtotal++;

  if(_mDRGEN==false)
	{
    if(document.layers)
    {
       document.captureEvents(Event.MOUSEDOWN|Event.MOUSEUP)
	   }
    document.onmousedown=startdrag
    document.onmouseup = stopdrag 
  	_mDRGEN=true;
	}
}

function stopdrag()
{
	__moving=false;
	mouseup=true;

	if(EXTfastdrag==true && _NSDIV!=false &&  _NSDIV.substr(0,6)!="imgdrg")
	{
		_move(_NStmp,_getpos(_NSDIV,"x"),_getpos(_NSDIV,"y"));
		_divVis("fstdrg","hide");
	}

	_NStmp=false;
	_NSDIV=false;
}

function _setNSRefresh()
{
  CurFunc="_setNSRefresh()";
  if(_disableNSRefresh==false)_setvirtual=true;
}

//for netscape..  move the div tags around (their positions will keep getting reset otherwise)
function _NSdivrender(which)
{
 CurFunc="_NSdivrender("+which+")";
 var i=0;

 if(which=="all")
	{
 while(i<_dragtotal)
   {
    if(document.layers)_move(_draggable[i],objsX[i],objsY[i]);
	i++;
   }
	}
	else _move(_draggable[which],objsX[which],objsY[which]); 

}

//fading functions
function setFade(div,dir)
{
	CurFunc="setFade("+div+","+dir+")";

	
	var tmpthread;
	if(user_thread!=1)tmpthread=_createThread(25);
	tmpVar=(dir==1)?0:1;

	if(dir==1)
	{
		if(EXTfade==true)
		{
			EXTfade=false
			_divVis(div,"show");
			 if(document.all)document.all[div].filters.alpha.opacity=0;
            else if(document.getElementById && _disableMozTrans==false)document.getElementById(div).style.Opacity=0;
			EXTfade=true
		}
		else _divVis(div,"show");
	}

	if(checkFunction(user_thread,'FADE("' +div+'",'+tmpVar+')')!=false)
	{
	  errorlog+="Conflict in FADE process, aborting FADE("+div+","+tmpVar+")\n" 
	  deleteFunction(user_thread,'FADE("' +div+'",'+tmpVar+')');
	  }
	addFunction(user_thread,'FADE("' +div+'",'+dir+')');

}

function FADE(div,inx)
{
  CurFunc="FADE("+div+","+inx+")";

  if(document.all)opacity=document.all[div].filters.alpha.opacity;
  else if(document.getElementById && _disableMozTrans==false)opacity=document.getElementById(div).style.Opacity;
  else opacity=(inx==1)?101:-1;

 if(inx==1)
 {
   (opacity<90)?opacity+=fdIN:deleteFunction(user_thread,'FADE("'+div+'",1)');
   }
 
 if(inx==0)
 { 
   if(opacity>0)opacity-=fdOUT;
   else
   {
	 if(EXTfade==true)
	   {
		 EXTfade=false;
		 _divVis(div,"hide");
		 EXTfade=true;
	   }
	 else _divVis(div,"hide")
     deleteFunction(user_thread,'FADE("'+div+'",0)');
     }
  }

   if(document.all)document.all[div].filters.alpha.opacity=opacity;
  else if(document.getElementById && _disableMozTrans==false)document.getElementById(div).style.Opacity=opacity;

}

//form writing
function _formItemWrite(name,text,div,form)
{
 if(document.all)eval("document.all." + name + ".value=text");
 var r=(document.layers)?_div(div).document.forms[form]:document.forms[form];
 eval("r." + name + ".value=text");  
}

function _formItemWriteInto(name,text,div,form)
{
 if(document.all)eval("document.all." + name + ".value+=text");
 else {
	 var r=(document.layers)?_div(div).document.forms[form]:document.forms[form];
     eval("r." + name + ".value+=text");  
 }
}

function _formItemRead(name,div,form)
{
  if(document.all)return eval("document.all." + name + ".value");
  var r=(document.layers)?_div(div).document.forms[form]:document.forms[form];
  return eval("r." + name + ".value");	
}

function font()
{
  var text;

  text=	getTxt("Please enter your text","");

  var size= prompt("Please enter the size you want the text to be","");
  var color=prompt("Please enter the color you want the text to be","");
  var font=prompt("Please enter the font","");

  putTxt("<font size=" + size + " color=#" + color + " face=" + font + ">" + text + "</font>");
}

function doTag(tag)
{
  var text;
 
  text = getTxt("Please enter your text","");
  putTxt("<" + tag + ">" + text + "</" + tag + ">");
}

function doLink()
{
  var isUrl;
  var url=getTxt("Please enter the hyperlink or email address:","");

  (url.indexOf("@")>0 || url.indexOf(".co")>0 || url.indexOf(".org")>0 || url.indexOf(".net")>0)?isUrl=true:isUrl=false;

  if(isUrl==false)
    {
	 name=url;
	 url=prompt("Please enter the hyperlink or email address:","");
	}
  else name=prompt("Please enter the text for this link:","");

  var prefix=(url.indexOf("@")>-1)?"mailto:":"http://";
  url=(url.indexOf("http://")<0 && url.indexOf("mailto:")<0)?prefix+url:url;
 
  putTxt("<a href=" + url + ">" + name + "</a>");
}

function getSel()
{
  if (document.getSelection) return document.getSelection();
  else if (document.selection) return document.selection.createRange().text;
}

function getTxt(str,prmpt)
{
  var txt="";
  txt=getSel()
  
  txt=(txt.length>0)?txt:prompt("" + str ,"" + prmpt);
  return txt;
}