///////////////////////////////////////////////////////////////////////
// JavaScript DHTML Utilies
// (c) 1998 Netscape Communications Corporation
// Written by Michael Bostock (mikebos@netscape.com)
///////////////////////////////////////////////////////////////////////

var isNav4, isIE4;
if (parseInt(navigator.appVersion.charAt(0)) >= 4) {
  isNav4 = (navigator.appName == "Netscape") ? true : false;
  isIE4 = (navigator.appName.indexOf("Microsoft") != -1) ? true : false;
}

///////////////////////////////////////////////////////////////////////
// Helper functions used by this library

function collapseArray(array, index, len) {
  for(var i = (index+1); i < len; i++)
    array[i-1] = array[i];
  array[i-1] = null;
  array.length--;
}

function getClip(layer) {
  if(isNav4) return layer.clip;
  var clip = new Array();
  var str = layer.style.clip;
  if(str) {
    var i = str.indexOf("(");
    clip.top = parseInt(str.substring(i + 1, str.length));
    i = str.indexOf(" ", i + 1);
    clip.right = parseInt(str.substring(i + 1, str.length));
    i = str.indexOf(" ", i + 1);
    clip.bottom = parseInt(str.substring(i + 1, str.length));
    i = str.indexOf(" ", i + 1);
    clip.left = parseInt(str.substring(i + 1, str.length));
  } else {
    clip.top = 0; clip.left = 0;
    clip.right = layer.style.pixelWidth;
    clip.bottom = layer.style.pixelHeight;
  }
  clip.width = clip.right - clip.left;
  clip.height = clip.bottom - clip.top;
  return clip;
}

function setClip(layer, l, r, t, b) {
  if(isNav4) {
    layer.clip.left = l; layer.clip.right = r;
    layer.clip.top = t;  layer.clip.bottom = b;
  } else {
    layer.style.pixelWidth = r-l;
    layer.style.pixelHeight = b-t;
    layer.style.clip = "rect("+t+","+r+","+b+","+l+")";
  }
}

///////////////////////////////////////////////////////////////////////
// Motions: Transitions & Movement

function Motion(direction, ex, length) {
  this.direction = direction; // U,D,L,R
  this.delay = 75;            // machine delay
  this.ex = ex;               // is the transition exclusive? (default: no)
  this.length = length;       // length of motion
  this.queue = new Array();
  this.queueInfo = new Array();
  this.id = _mQueue.length;
  this.inmotion = false;
  _mQueue[_mQueue.length] = this;
  this.applyMovement = callApplyMovement;
  this.applyTransition = callApplyTransition;
  this.changeAttribute = callChangeAttribute;
  this.eval = callEval;
  this.setInfo = setInfo;
  this.setTransInfo = setTransInfo;
}

// _mQueue array to store motion objects in use
var _mQueue = new Array();

///////////////////////////////////////////////////////////////////////
// Motion Object: eval

function callEval(str) {
  this.queue[this.queue.length] = true;
  var info = new Array();
  info.type = "eval";
  info.str = str;
  this.queueInfo[this.queueInfo.length] = info;
  if(this.inmotion == false) {
    this.inmotion = true;
    applyMovement(this.id);
  }
}

///////////////////////////////////////////////////////////////////////
// Motion Object: changeAttribute

function callChangeAttribute(attribute, value) {
  this.queue[this.queue.length] = true;
  var info = new Array();
  info.type = "attr";
  info.attribute = attribute;
  info.value = value;
  this.queueInfo[this.queueInfo.length] = info;
  if(this.inmotion == false) {
    this.inmotion = true;
    applyMovement(this.id);
  }
}

function changeAttribute(attribute, value, trans) {
  eval('switch(attribute) {'+
    'case "direction": trans.direction = value; break;'+
    'case "ex": trans.ex = value; break;'+
    'case "length": trans.length = value; break;'+
  '}');
}

function waitChangeAttribute(attribute, value, id) {
  if(_mQueue[id].inmotion == false)
    changeAttribute(attribute, value, _mQueue[id]);
  else
    setTimeout("waitChangeAttribute(\""+attribute+"\",\""+value+"\","+id+")",
	       _mQueue[id].delay);
}


///////////////////////////////////////////////////////////////////////
// Motion Object: applyMovement

function callApplyMovement(layer, x, y) {
  this.queue[this.queue.length] = layer;
  var info = new Array();
  info.dstX = x;
  info.dstY = y;
  info.type = "laye";
  info.set = false;
  this.queueInfo[this.queueInfo.length] = info;
  if(this.inmotion == false) {
    this.inmotion = true;
    applyMovement(this.id);
  }
}

function setInfo(layer, info) {
  var dx, dy;
  if(this.direction.indexOf("H") == -1) {
    if(isNav4) info.dstX = layer.left;
    else if(isIE4) info.dstX = layer.style.pixelLeft;
  }
  if(this.direction.indexOf("V") == -1) {
    if(isNav4) info.dstY = layer.top;
    else if(isIE4) info.dstY = layer.style.pixelTop;
  } 
  if(isIE4) {
    dx = info.dstX-layer.style.pixelLeft;
    dy = info.dstY-layer.style.pixelTop;
  } else if(isNav4) {
    dx = info.dstX-layer.left;
    dy = info.dstY-layer.top;
  }
  if(dy != 0) {
    info.ychunk = Math.round(dy*this.delay/(this.length*1000));
    if(info.ychunk == 0 && dy < 0) info.ychunk = -1;
    else if(info.ychunk == 0) info.ychunk = 1;
  }
  if(dx != 0) {
    info.xchunk = Math.round(dx*this.delay/(this.length*1000));
    if(info.xchunk == 0 && dx < 0) info.xchunk = -1;
    else if(info.xchunk == 0) info.xchunk = 1;
  }
  info.set = true;
}

function applyMovement(id) {
  var trans = _mQueue[id];
  var max = 1, collapse;
  for(var i = 0; i < max; i++) {
    collapse = false;
    eval('switch(trans.queueInfo[i].type) {'+
'   case "attr":'+
'     changeAttribute(trans.queueInfo[i].attribute,'+
'     		      trans.queueInfo[i].value, trans);'+
'     collapse = true;'+
'     break;'+
'   case "eval":'+
'     eval(trans.queueInfo[i].str);'+
'     collapse = true;'+
'     break;'+
'   case "tran":'+
'     if(!trans.queueInfo[i].set)'+
'	trans.setTransInfo(trans.queue[i], trans.queueInfo[i]);'+
'     collapse = step(trans.queue[i], trans.queueInfo[i]);'+
'     break;'+
'   case "laye":'+
'     if(!trans.queueInfo[i].set)'+
'	trans.setInfo(trans.queue[i],trans.queueInfo[i]);'+
'     collapse = move(trans.queue[i], trans.queueInfo[i]);'+
'     break;'+
'   default: self.status = "Error: invalid queue type."; break;'+
'   }');
    if(collapse) {
      collapseArray(trans.queue, i, trans.queue.length);
      collapseArray(trans.queueInfo, i, trans.queueInfo.length);      
      if(!trans.ex) i--;
    }
    if(!trans.ex) max = trans.queue.length;
  }
  if(trans.queue.length > 0)
    setTimeout("applyMovement("+id+");", trans.delay);
  else trans.inmotion = false;
}

function chunkValue(max, current, chunk) {
  var mult = 1;
  if(chunk < 0) mult = -1;
  if(mult*current < mult*max - mult*chunk) return (current + chunk);
  else return max;
}

function move(layer, info) {
  var ret = true;
  var layertop, layerleft;
  if(isNav4) {
    layertop = layer.top;
    layerleft = layer.left;
  } else if(isIE4) {
    layertop = layer.style.pixelTop;
    layerleft = layer.style.pixelLeft;
  }
  if(layertop != info.dstY) {
    layertop = chunkValue(info.dstY, layertop, info.ychunk);
    ret = false;
  }
  if(layerleft != info.dstX) {
    layerleft = chunkValue(info.dstX, layerleft, info.xchunk);
    ret = false;
  }
  if(isNav4) {
    layer.top = layertop;
    layer.left = layerleft;
  } else if(isIE4) {
    layer.style.pixelTop = layertop;
    layer.style.pixelLeft = layerleft;
  }
  return ret;
}

///////////////////////////////////////////////////////////////////////
// Motion Object: applyTransition

function callApplyTransition(layer, fadein, override, l, r, t, b) {
  this.queue[this.queue.length] = layer;
  var info = new Array();
  info.fadein = fadein;
  info.type = "tran";
  info.set = false;
  if(override) {
    info.dstL = l; info.dstR = r;
    info.dstT = t; info.dstB = b;
    layer.gotOrig = true;
    layer.origleft = l; layer.origright = r;
    layer.origtop = t;  layer.origbottom = b;
  }
  if(!layer.gotOrig) {
    var clip = getClip(layer);
    layer.gotOrig = true;
    layer.origleft = clip.left; layer.origright = clip.right;
    layer.origtop = clip.top;   layer.origbottom = clip.bottom;
  }
  this.queueInfo[this.queueInfo.length] = info;  
  if(this.inmotion == false) {
    this.inmotion = true;
    applyMovement(this.id);
  }
}

function setTransInfo(layer, info) {
  var dir = new Array();
  dir.left = this.direction.indexOf("L") != -1;
  dir.right = this.direction.indexOf("R") != -1;
  dir.top = this.direction.indexOf("U") != -1;
  dir.bottom = this.direction.indexOf("D") != -1;
  var w, h;
  if(this.fadein == false) {
    var clip = getClip(layer);
    w = (clip.right-clip.left);
    h = (clip.bottom-clip.top);
  } else {
    w = layer.origright - layer.origleft;
    h = layer.origbottom - layer.origtop;
  }
  var l, r, t, b;
  if(dir.left && dir.right) {    l = w/2; r = w/2; }
  else if(dir.left) {            l = w;   r = w;   }
  else if(dir.right) {           l = 0;   r = 0;   }
  else {                         l = 0;   r = w;   }
  if(dir.top && dir.bottom) {    t = h/2; b = h/2; }
  else if(dir.top) {             t = h;   b = h;   }
  else if(dir.bottom) {          t = 0;   b = 0;   }
  else {                         t = 0;   b = h;   }
  l = Math.round(l); r = Math.round(r);
  t = Math.round(t); b = Math.round(b);
  if(info.fadein) {
    setClip(layer, l, r, t, b);
    if(layer.style) layer.style.visibility = "visible";
    else layer.visibility = "show";
    if(!info.dstL && info.dstL != 0) l = layer.origleft;
    else l = info.dstL;
    r = info.dstR || layer.origright;
    t = info.dstT || layer.origtop;
    b = info.dstB || layer.origbottom;
  }
  info.dstL = l; info.dstR = r;
  info.dstT = t; info.dstB = b;
  var clip = getClip(layer);
  info.lchunk = Math.round((l-clip.left)*this.delay/(this.length*1000)); 
  info.rchunk = Math.round((r-clip.right)*this.delay/(this.length*1000));  
  info.tchunk = Math.round((t-clip.top)*this.delay/(this.length*1000));  
  info.bchunk = Math.round((b-clip.bottom)*this.delay/(this.length*1000));  
  info.set = true;
}

function step(layer, info) {
  var ret = true;
  var clip = getClip(layer);
  var l = clip.left; var r = clip.right;
  var t = clip.top;  var b = clip.bottom;
  if(clip.top != info.dstT) {
    t = chunkValue(info.dstT, clip.top, info.tchunk);
    ret = false;
  }
  if(clip.left != info.dstL) {
    l = chunkValue(info.dstL, clip.left, info.lchunk);
    ret = false;
  }
  if(clip.right != info.dstR) {
    r = chunkValue(info.dstR, clip.right, info.rchunk);
    ret = false;
  }
  if(clip.bottom != info.dstB) {
    b = chunkValue(info.dstB, clip.bottom, info.bchunk);
    ret = false;
  }
  setClip(layer, l, r, t, b);
  return ret;
}

///////////////////////////////////////////////////////////////////////
// Motion Object: the end
