
var ns4 = (document.layers) ? 1:0
var ie4 = (document.all) ? 1:0

var allDObjects = new Array();
var dObjectCount = 0;
var Xpos, Ypos;
var currZIndex = 0;

// for arranging sequential
// function calls
var seq = new Array();
var seqPause = new Array();
var seqCount = 0;

// for saving a longer path
var savePath = false;
var globPathArr = new Array();



// dObject provides the functionality for the page
// objects. The name has to match the name of the 
// page object. dragable is a boolean that makes
// the objects sensitive to mouse clicks etc. for
// now this is a static property meaning if one 
// is dragable then they all are.

function dObject( dName, x, y, dWidth, dHeight, dragable )
{

  this.ns4 = (document.layers) ? 1:0
  if( this.ns4 )
  {
    this.lObject = eval( 'document.' + dName );
    this.zoomSize = "document." + dName + ".document.write('<DIV ID=' + this.lObject.dName + ' name=' + this.lObject.dname + ' style=\"position:absolute; font-family:arial; font-weight: bold; font-size:' + size + 'pt; color:' + this.lObject.color + '; left: ' + this.lObject.getLeft() + '; top: ' + this.lObject.getTop() + ';\">' + this.lObject.text + '</DIV>')";
	                                            
    this.tShow = 'show';
    this.tHide = 'hide';

    document.captureEvents(Event.MOUSEMOVE | Event.MOUSEDOWN | Event.MOUSEUP);

  }
  else
  {
    this.lObject = document.all[ dName ].style;
    this.zoomSize = 'this.lObject.fontSize = size';

    this.tShow = 'visible';
    this.tHide = 'hidden';
  }


  document.onmousedown=mDown;
  document.onmouseup=mUp;
  document.onmousemove=mMove;


  this.lObject.width = dWidth;
  this.lObject.height = dHeight;

  this.dName = dName;
  this.count = dObjectCount;
  this.path =  new Array();
  this.zIndex = currZIndex;

// these are for the go routines
// for sliding the object across the page

  this.xJumps = 0;
  this.yJumps = 0;
  this.sizeOfStep = 1;

// these are for the crazy fly around routine

  this.delay = 60;
  this.yAmpl = 10;
  this.yMax = 20;
  this.step = .1;
  this.ystep = .2;
  this.currStep = 0;
  this.tAmpl = 1;
  this.j = 0;
  this.Xpos = x;
  this.Ypos = y;

  if (ns4) 
  {
    this.yBase = window.innerHeight / 3;
    this.xBase = window.innerWidth / 3;
  }
  else 
  {
    this.yBase = document.body.offsetHeight / 3;
    this.xBase = document.body.offsetWidth / 3;
  }
  this.intervalID = null;

// these are the object functions

  this.show = show;
  this.hide = hide;
  this.go = go;
  this.swoop = swoop;
  this.setSwoop = setSwoop;
  this.stopSwoop = stopSwoop;
  this.circle = circle;
  this.animate = animate;
  this.setZoom = setZoom;
  this.zoom = zoom;
  this.setDragable = setDragable;
  this.setPath = setPath;

  
// these are functions that are optionally
// defined by the client that are called when
// mouse events happen over the onject. The
// client has to send in the function names
// in the following set function

   this.lObject.objectMouseDown = null;
   this.lObject.objectMouseOver = null;
   this.lObject.objectMouseUp = null;
   this.lObject.objectMouseOut = null;
   
   this.setMouseDown = setMouseDown;
   this.setMouseUp = setMouseUp;
   this.setMouseOver = setMouseOver;
   this.setMouseOut = setMouseOut;
   this.moveMe = moveMe;   

   this.mouseOver = false;
  

// this is the array that is used for capturing the 
// mouse events as they can't belong to an object

  this.lObject.dragable = false;
  this.lObject.dragable = dragable;
  this.moveMe = dragable;

  allDObjects[dObjectCount] = this.lObject;

  allDObjects[dObjectCount].moveMe = moveMe;
  allDObjects[dObjectCount].moveMe( x, y );
  allDObjects[dObjectCount].getLeft = getLeft;
  allDObjects[dObjectCount].getTop = getTop;
  allDObjects[dObjectCount].dName = dName;
  allDObjects[dObjectCount].sel = false;
  allDObjects[dObjectCount].zIndex = dObjectCount;
  
  
  dObjectCount++;
  

  currZIndex++;


}


// functions for defining original mouse
// action functions

function setMouseUp( funcName )
{
   this.lObject.objectMouseUp = funcName;
}

function setMouseDown( funcName )
{
   this.lObject.objectMouseDown = funcName;
}

function setMouseOver( funcName )
{
   this.lObject.objectMouseOver = funcName;
}

function setMouseOut( funcName )
{
   this.lObject.objectMouseOut = funcName;
}



//for netscape reasons

function setZoom( fontSize, fontColor, fontText )
{

  if( this.ns4 )
  {
    this.lObject.fontSize = fontSize;
    this.lObject.color = fontColor;
    this.lObject.text = fontText;
  }

}

function zoom( size, endSize, inc, pause, nextOp, commands )
{

  if (size > endSize)
     inc = -inc;

  if ( Math.abs(size - endSize) > Math.abs(inc) )
  {
    size += inc ;
    eval(this.zoomSize);

    if( this.ns4 )
      eval("document." + this.dName + ".document.close()");

    setTimeout( this.lObject.dName + ".zoom(" + size + ", " + endSize + ", " + Math.abs(inc) + ", " + pause + ", '" + nextOp + "','" + commands + "')" , pause)
  }else{
     nextOperation( nextOp, commands ); 
  }
}


// This subroutine takes the interval and moves the
// object along path. When it is done it initiates
// the next opertation which are operations that 
// are chained with a specified time between them
// and checks the next command which are operation
// that are chained such that as the next command in 
// the chain gets called after the form in finished 

function animate( interval, arrCount, nextOp, commands )
{
   if(this.path[arrCount])
   {
      this.lObject.moveMe(this.path[arrCount].x - parseInt(parseInt(this.lObject.width)/2) , this.path[arrCount].y - parseInt(parseInt(this.lObject.height)/2));
      arrCount++;
   }

   if( arrCount < this.path.length )
   {
     setTimeout(this.dName + ".animate(" + interval + ", " + arrCount + ", '" + nextOp + "'" + ",'" + commands + "')", interval);
   }else{
     this.path = new Array();  
     nextOperation( nextOp, commands );   

   }

   

}

function setPath()
{
   this.path = globPathArr;
   globPathArr = new Array();
}



// commandSet objects contain chains of commands that
// get executed one after another

function commandSet()
{

  this.commandsCount = 0;
  this.checkCommands = checkCommands;
  this.addCommand = addCommand;
  this.executeCommands = executeCommands;

  this.commands = new Array();
  
}


// executes the next command in the chain if there is one

function checkCommands()
{
   if(this.commandsCount < this.commands.length)
   {
     this.commandsCount++;
     eval(this.commands[this.commandsCount]);
   }
}


// this is an array to holds a queue of commands
// that get called one after another


function addCommand( func)
{
  this.commands[this.commands.length] = func; 
}

// starts off the chain of commands

function executeCommands()
{
    eval(this.commands[0]);
}

// fills the path array with x and y positions
// that will take the object from its current 
// position to the destination position. nextOp
// is the optional operation to be performed when
// the the animate function finishes moving the
// object along the path.

function go(destX, destY, numOfStep, lPause, nextOp, commands)
{

  var distanceX = Math.abs(this.lObject.getLeft() - destX);
  var distanceY = Math.abs(this.lObject.getTop() - destY);


  var xStep = distanceX/numOfStep;
  var yStep = distanceY/numOfStep;  

  var dirLeft = (this.lObject.getLeft() < destX)? 'right':'left';
  var dirTop = (this.lObject.getTop() < destY)? 'down':'up';

  var addSubLeft = (dirLeft == 'left')?-xStep:xStep;
  var addSubTop = (dirTop == 'up')?- yStep:yStep;

  var x = this.lObject.getLeft();
  var y = this.lObject.getTop();

  this.path = new Array();

  for (var i = 0; i < numOfStep; i++) 
  {
    x += addSubLeft;
    y += addSubTop;
    this.path[i] = new pos(x, y);
  }

  this.animate(lPause, 0, nextOp, commands);
	
}

// show and hide for appearing and disappearing
// also allows for passing through next operation

function show( nextOp, commands )
{
   this.lObject.visibility = this.tShow;
   nextOperation( nextOp, commands );
}

function hide( nextOp, commands )
{
   this.lObject.visibility = this.tHide;
   nextOperation( nextOp, commands );
}


// mDown is the function that gets called whenever
// the mouse goes down on an object or no! If you mouse
// down on an object then swoop stops. the objects sel attribute
// gets toggled if the object is clicked on.

function mDown( evnt )
{
  Xpos=(ns4)?evnt.pageX:window.event.x;
  Ypos=(ns4)?evnt.pageY:window.event.y;


  for( var i = 0; i < allDObjects.length; i++ )
  {
    if( Xpos > allDObjects[i].getLeft() && Xpos < ( parseInt(allDObjects[i].width) + allDObjects[i].getLeft()) && Ypos > allDObjects[i].getTop() && Ypos < ( parseInt(allDObjects[i].height) + allDObjects[i].getTop()))
    {  
      allDObjects[i].sel = !allDObjects[i].sel;  
      allDObjects[i].clickedX = Xpos - allDObjects[i].getLeft();
      allDObjects[i].clickedY = Ypos - allDObjects[i].getTop();
      
      if(allDObjects[i].objectMouseDown )
        allDObjects[i].objectMouseDown(Xpos, Ypos, allDObjects[i].dName);
      
      if(allDObjects[i].sel && allDObjects[i].dragable)
      {
        //eval(allDObjects[i].dName + '.stopSwoop()');
        allDObjects[i].zIndex = ++currZIndex;
      } 
    }
  }

}






// This gets called every time the mouse moves.
// I want to add a save path toggle that will save a 
// path and possibly pass that path to an object to 
// traverse.

function mMove( evnt )
{
  Xpos=(ns4)?evnt.pageX:event.x;
  Ypos=(ns4)?evnt.pageY:event.y;

  if(savePath)
  {
    globPathArr[globPathArr.length] = new pos( Xpos, Ypos );
  }

  for( var i = 0; i < allDObjects.length; i++ )
  {
  
    if( Xpos > allDObjects[i].getLeft() && Xpos < ( parseInt(allDObjects[i].width) + allDObjects[i].getLeft()) && Ypos > allDObjects[i].getTop() && Ypos < ( parseInt(allDObjects[i].height) + allDObjects[i].getTop()))
    {    
      if(allDObjects[i].objectMouseOver )
      {
        allDObjects[i].objectMouseOver(Xpos, Ypos);    
        allDObjects[i].mouseOver = true;
      }
    }else{
      if(allDObjects[i].objectMouseOut &&  allDObjects[i].mouseOver)
      {
        allDObjects[i].objectMouseOut(Xpos, Ypos, allDObjects[i].dName);  
        allDObjects[i].mouseOver = false;
      }
    }
    
    if( allDObjects[i].sel && allDObjects[i].dragable )
    {
      allDObjects[i].moveMe( Xpos - allDObjects[i].clickedX, Ypos - allDObjects[i].clickedY);
    }
  }

}

// sets dragability of objects

function setDragable( drag )
{
  this.lObject.dragable = drag;
}


// as above but when the mouse goes up

function mUp( evnt )
{
  

  Xpos=(ns4)?evnt.pageX:window.event.x;
  Ypos=(ns4)?evnt.pageY:window.event.y;

  var coords = new Array();
  coords[0] = Xpos;
  coords[1] = Ypos;
  
    for( var i = 0; i < allDObjects.length; i++ )
  {
    
    if( allDObjects[i].sel && allDObjects[i].dragable )
    {
      allDObjects[i].sel = false; 
      if(allDObjects[i].objectMouseUp)
        allDObjects[i].objectMouseUp(Xpos, Ypos, allDObjects[i].dName);
    }
  }
  
  
  
  

  return coords;

}

// a little short cut for making location jumps

function moveMe( x, y, nextOp, commands ){
  this.left=x;
  this.top=y;
  nextOperation( nextOp, commands );
}



// these two return the coordinates of the object

function getLeft(){
  var x=( ns4 )? this.left:this.pixelLeft;
  return parseInt(x);
}
function getTop(){
  var y=( ns4 )? this.top:this.pixelTop;
  return parseInt(y);
}

// these crazy function makes things fly around the screen
// if you don't setSwoop you swoop in default mode

var chaseMouse = false;

function setSwoop( delay, yAmpl, yMax, step, ystep, tAmpl, x, y, yBase, xBase, followMouse )
{

  chaseMouse = followMouse;
  this.delay = delay;
  this.yAmpl = yAmpl;
  this.yMax = yMax;
  this.step = step;
  this.ystep = ystep;
  this.tAmpl = tAmpl;
  this.Xpos = x;
  this.Ypos = y;
  this.yBase = yBase;
  this.xBase = xBase;
}

function swoop() 
{

  var sX=( chaseMouse )? Xpos:this.Xpos;
  var sY=( chaseMouse )? Ypos:this.Ypos;

  this.lObject.top = sY + 
  Math.cos((20*Math.sin(this.currStep/(20)))+70)*this.yBase*(Math.sin(10+this.currStep/10)+0.2)*Math.cos((this.currStep + 25)/10);
  
  this.lObject.left = sX + 
  Math.sin((20*Math.sin(this.currStep/20))+70)*this.xBase*(Math.sin(10+this.currStep/(10))+0.2)*Math.cos((this.currStep + 25)/10);
  this.currStep += this.step;

  this.intervalID = setTimeout(this.dName + ".swoop()", this.delay) ;
  
}


function stopSwoop( nextOp, commands )
{
  clearInterval(this.intervalID);
  nextOperation( nextOp, commands );
}



function nextOperation( op, commands )
{
   if( op != 'null' && op != 'undefined' && op != '' && op)
     eval( op );

   if(commands != 'null' && commands != 'undefined' && commands != '' && commands)  
   {
         eval(commands + '.checkCommands()');
   }

}


// here is my attempt at a circle function


function circle(radius, angle0, angle1, steps, interval, upDown, nextOp, commands) 
{

  dangle = angle1 - angle0;
  sangle = dangle / steps;
  x = this.lObject.getLeft();
  y = this.lObject.getTop();
  cx = x - radius * Math.cos(angle0 * Math.PI / 180);
  cy = y + radius * Math.sin(angle0 * Math.PI / 180);
  this.path = new Array();

  for (var i = 0; i < steps; i++) 
  {
    angle0 += sangle;
    x = cx + radius * Math.cos(angle0 * Math.PI / 180);
    y = cy - radius * Math.sin(angle0 * Math.PI / 180);
    this.path[i] = new pos(x, y);
  }

  if(upDown == 'd')
  {
     this.path.reverse();
  }

  this.animate(interval, 0, nextOp, commands);
}

// a helper function for creating the path in the circle function
// and perhaps others to come

function pos( x, y )
{

   this.x = x;
   this.y = y;

}





// this function is to help call the webtoyz functions so that 
// they happen in time ordered sequence rather than at the same time



function sequence( name )
{

  this.addSequence = addSequence;
  this.sequenceGo = sequenceGo;
  this.sequenceReset = sequenceReset;

  this.name = name;
  this.seqCount = 0;
  this.seq = new Array();
  this.seqPause = new Array();

}

function sequenceReset( backTo )
{
  this.seqCount = backTo;
}

function addSequence( func, pause )
{

  this.seqPause[this.seqPause.length] = pause;
  this.seq[this.seq.length] = func;    

}

function sequenceGo( commands, nextCommandPause )
{
  if(this.seqCount < this.seq.length)
  {
    eval(this.seq[this.seqCount]);
    this.seqCount++;
    setTimeout(this.name + ".sequenceGo()", this.seqPause[this.seqCount-1]);   
  }

    if(commands)
	  setTimeout( "nextOperation( '', '" + commands + "')", nextCommandPause);
  
}

