/* -------------------------------------------------------- */
/* JS-Navigation / crossbrowser + crossplatform   ver 1.14  */
/* -------------------------------------------------------- */
/* Created:      2002-04-29                                 */
/* Updated:      08.01.2003 17:24:10  by Donald Lessau (DL) */
/* -------------------------------------------------------- */
/* Copyright (c) 2002-03 by D. Lessau   (donald@xbeat.net)  */
/* -------------------------------------------------------- */
// PC:  IE55, IE60, NS60, NS62, NS70, Opera601, Opera6.05, Opera7.0
// Mac: IE50, IE51, NS60, NS62 [OS9, OSX]

function BrowserSniff(){  /*BrowserSniff (c) Donald Lessau, ver 20030110*/
  this.agent=navigator.userAgent;
  // checking
  //this.agent="Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC)"
  //this.agent="Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 4.0)"
  //this.agent="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
  //this.agent="Mozilla/5.0 (Windows; U; Win98; en-US; m18) Gecko/20001108 Netscape6/6.0"
  //this.agent="Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:0.9.4.1) Gecko/20020508 Netscape6/6.2.3 (CK-SillyDog)"
  //this.agent="Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.1) Gecko/20020823 Netscape/7.0"
  //this.agent="Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01"
  //this.agent="Mozilla/4.71 (Windows 95;US) Opera 3.62 [en]"
  //this.agent="Mozilla/4.0 (compatible; MSIE 5.0; Windows XP) Opera 6.05 [en]"
  //this.agent="Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows XP) Opera 7.0 [en]"
  //this.agent="Googlebot/2.1 (+http://www.googlebot.com/bot.html)"

  var idxMSIE = this.agent.indexOf("MSIE");
  var idxNN = this.agent.indexOf("Netscape");
  var idxNN6 = this.agent.indexOf("Netscape6");
  var idxOP = this.agent.indexOf("Opera");
  if (idxOP>-1) {
    this.name = "Opera";
    this.ver = formatVer(this.agent, idxOP + 6);
  } else if (idxMSIE>-1) {
    this.name = "Internet Explorer";
    this.ver = formatVer(this.agent, idxMSIE + 5);
  } else if (idxNN6>-1) {
    this.name = "Netscape";
    this.ver = formatVer(this.agent, idxNN6 + 10);
    var ns6 = true;
  } else if (idxNN>-1) {
    this.name = "Netscape";
    this.ver = formatVer(this.agent, idxNN + 9);
  } else {
    this.name = "Unknown";
    //detect Netscape 4.7+    
    if (navigator.appName=="Netscape" && parseFloat(navigator.appVersion)>=4.7) {
      this.name = "Netscape";
      this.ver = parseFloat(navigator.appVersion);
      var ns47 = true;
    }  
  }
  // handy vars
  this.ie = (this.name == "Internet Explorer");
  this.ie50 = this.ie && this.agent.indexOf("MSIE 5.0")>-1;

  this.ns = (this.name == "Netscape");
  this.ns47 = this.ns && ns47==true;
  this.ns6 = this.ns && ns6==true;
  
  this.op = (this.name == "Opera");
  this.op6 = this.op && parseInt(this.ver) == 6;
  this.op7 = this.op && parseInt(this.ver) >= 7;
  
  this.mac = (this.agent.indexOf("Mac")>-1);
  this.platform = this.mac?"Mac":"PC";
  this.bw = this.name + this.ver;
  this.bp = this.bw + "-" + this.platform;
  this.dom=document.getElementById?true:false;
  this.px = this.dom&&!this.op?"px":""; // CSS pixels
}
function formatVer(agent, pos) {
  var verMajor="?", verMinor="0", verRevision="0";
  verMajor = parseInt(agent.substring(pos))
  if (agent.length >= pos+2) {
    verMinor = parseInt(agent.substring(pos+2, pos+4));
    if (verMinor > 0) {
      if (agent.substring(pos+2, pos+3) == "0") {verMinor = "0" + verMinor};
      var verRevision = parseInt(agent.substring(pos+4));
      if (verRevision > 0) {
        verMinor +=  "." + verRevision;
      }
    }
  }
  return verMajor + "." + verMinor;
}
var bw = new BrowserSniff();

//debug zone ----------------------------------------------------------------------------
var debug, counter = 0;
//MacIE50, Opera cannot handle debug layers before pageload
//if (!(bw.mac && bw.ie50) || bw.op) debug = new cDebug();  //'''rem line out to hide debug
function cDebug() {  /* debug box constructor */
  document.write("<div id='debug' style='position:absolute; FONT-FAMILY:  Trebuchet MS; FONT-WEIGHT: bold; font-size: 11px; left:10px; top:450px; width:750px; height:100px; background:#666666;visibility:visible;'>" + "ver: " + bw.ver + "<br>agent: " + bw.agent + "</div>");
  document.write("<div id='debug2' style='position:absolute; FONT-FAMILY: Trebuchet MS; FONT-WEIGHT: bold; font-size: 11px; left:10px; top:530px; width:750px; height:20px; background:#ff0000;visibility:visible;'>" + "Browser-Platform: " + bw.bp + "</div>");
  this.box = document.getElementById("debug");
  this.box2 = document.getElementById("debug2");
}
// debugprint nodo in Opera
function debugprint(msg) {if (debug) debug.box.innerHTML = msg; }
function debugcount(msg) {if (debug) {counter++; debug.box2.innerHTML = "#" + counter + ":" + msg;}}
function debugtitle(msg) {counter++; document.title = "#" + counter + ":" + msg;}
// ---------------------------------------------------------------------------------

// =================================================================================
// configuration
var idHideOnCollision = conf.idHideOnCollision;  // IDs of elements to hide, commaseparated.
var closeMenuDelay = 300; //msec delay before menu disappears
var clrOver = conf.clrOver; //mouseover color
var clrOut = conf.clrOut;   //mouseout color: empty to return to default color
if (bw.op6) clrOut = conf.clrOutHard; //Opera6
//var clrOut = "#ffffff";   //mouseout color
var fHotTracking = 1;     //hottracking (keep current selection path shaded)
// style bits the 'iStyle' parameter in function menOverTR()
var cSkipColoring = 1;    //skip mouseover coloring
var cPopDown = 2;         //pop first popup downwards
// global vars
var elemCurItem;          //current item (TR) where cursor is at
var elemCurMenuAt;        //current menu (DIV) where cursor is at
//note: cursor change not supported in Opera6
var handcursor = bw.ns?"pointer":"hand";
// note: standard array methods push and pop are NOT supported by IE5-Mac!
var stackMenu = [0];      //currently visible DIVs
var stackItem = [0];      //currently visible TRs (treepath)
var stackColored = [0];   //currently colored items
var curLevelAt = 0;       //current level
var fActive = false;    	//user action flag for delay
var closeTimeoutID = 0;		//for delay

// =================================================================================
// internal functions
var bodyMargin = new getBodyMargin();
function getBodyMargin() {
  // read margins once from CSS styles
  // expects (a) ONE stylesheet, (b) BODY rule to be the FIRST!
  // [this function is needed only by IE5-Mac]
  var theRules = new Array(); //document.styleSheets[0] only
  getTheRules();
  function getTheRules() {
  	if (!document.styleSheets) return;      /*Opera*/
  	if (document.styleSheets[0].cssRules)   /*NS6, IE5/Mac*/
  		theRules = document.styleSheets[0].cssRules
  	else if (document.styleSheets[0].rules) /*IE4+/WinMac*/
  		theRules = document.styleSheets[0].rules
  	else return
  }
  if (theRules.length > 0) {
    this.Left = parseInt(theRules[0].style.marginLeft);
    this.Top = parseInt(theRules[0].style.marginTop);
  } else {
    this.Left = 0;
    this.Top = 0;
  }
}

function getBrowserWindowSize() {
// 20020512: returns object with inner window size and scroll offset
  if (bw.ns) {
    // Netscape
    // scrollbars are NOT taken care off by innerWidth/innerHeight
    this.width = window.innerWidth;
    this.height = window.innerHeight;
    this.scrollX = window.scrollX;  //alternativ: window.pageXOffset
    this.scrollY = window.scrollY;  //alternativ: window.pageYOffset
  } else if (bw.op6) {
    // Opera6
    this.width = window.innerWidth;
    this.height = window.innerHeight;
    this.scrollX = window.pageXOffset;
    this.scrollY = window.pageYOffset;
  } else {
    // other browsers
    // scrollbars are taken care off by clientWidth/clientHeight
    // note: offsetWidth returns a value 4 pixels larger than clientWidth (= 2 x 3D-borders)
    this.width = document.body.clientWidth;
    this.height = document.body.clientHeight;
    this.scrollX = document.body.scrollLeft;
    this.scrollY = document.body.scrollTop;
  }
}

function getAbsoluteOffset(elem) {
// 20020511: x/y offsets within page
// PC:  +IE55, +NS60, +NS62, Opera 7
// Mac: +IE50, +IE51, +NS60+
  var offsetX = 0, offsetY = 0;
  var sDepthX = "", sDepthY = "";
  // 20030107: pass elem, not id
  //var elem = document.getElementById(id);

  if (elem.offsetParent) {
    // IE55, NS60-level 1, NS62: walk up the object hierarchy
		// MacIE55 is here, too
    // Opera 7
  	while (elem.offsetParent) {

      offsetX += elem.offsetLeft;
      offsetY += elem.offsetTop;

      // for debug only
      sDepthX += elem.tagName + ":" + elem.offsetLeft + ",";
      sDepthY += elem.tagName + ":" + elem.offsetTop + ",";

      elem = elem.offsetParent;
    }

    // for NS60-level 1 PC: add body offset (is 0 in other browsers, also on Mac)
    // Opera6 would NaN here
    if (bw.ns) {
    	offsetX += document.body.offsetLeft;
     	offsetY += document.body.offsetTop;
    }

		// MacIE50 and MacIE51 need to add the body style offsets
		if (bw.mac && bw.ie) {
 			offsetX += bodyMargin.Left
 			offsetY += bodyMargin.Top
		}


  } else {
    // NS60-level 2ff: elem.offsetParent is Null for layer 2 ff
    // in this case offsetLeft/Top is all we need
    offsetX += elem.offsetLeft;
    offsetY += elem.offsetTop;

    // for debug only
    sDepthX += elem.tagName + ":" + elem.offsetLeft + ",";
    sDepthY += elem.tagName + ":" + elem.offsetTop + ",";
  }
  // build return-struct
  this.x = offsetX;
  this.y = offsetY;
  // for debug only
  this.sDepthX = sDepthX;
  this.sDepthY = sDepthY;
}

// =================================================================================
// event-driven functions
function menOut() {
  // issue: event is triggered *still within* the DIV when cursor is over grey line.
  // solution: onMouseOver="menOver();"
  fActive = false;
  closeTimeoutID = window.setTimeout("closeMenu()", closeMenuDelay);
}
function menOver() {
    window.clearTimeout(closeTimeoutID);
}
function closeMenu() {
  if (fActive) {
    // keep open
    window.clearTimeout(closeTimeoutID);
  } else {
    //ensure style undo for level 1 TR (happens when we mouseOut there)
    //stackitem.1.style error fix:
    if (stackItem[1]) {
      if (stackColored[1]) colorTR(stackItem[1],clrOut);
    }
    //close all menus above level 2
    curLevelAt = 1;
    for (var i = stackMenu.length - 1; i > curLevelAt; i--) {
      stackMenu[i].style.visibility = "hidden";
      stackMenu.length--; //pop not supported by IE5-Mac
      stackItem.length--;
      // uncolor
      if (stackColored[i]) {colorTR(stackColored[i],clrOut); stackColored[i] = null;}
    }
    // reinit
    stackMenu = [0];
    stackItem = [0];

    //20020730: show element (pass empty string for layer)
    showElement(true, idHideOnCollision, "");

  }
}

function colorTR(elTR, clr) { //20030107
  if (bw.op7) {
    // Opera7 can't color a TR behind a TD, resp cannot have transparent TDs
    // so we color all TDs
    for (var i=0; i < elTR.children.length; i++) {
      elTR.children[i].style.backgroundColor = clr;
    }
  } else {
    // all other browsers
    elTR.style.backgroundColor = clr;
  }
}

function menOverTR(id_self,id_layer,iStyle) {
  // id_self        id of current table row (= this.id of event)
  // id_layer       id of child div (the layer to be shown)
  // iStyle         composite of style bits (optional), values see above
  var dmsg = ""; //debug
  var x = 0, y = 0;
  var elSelf=document.getElementById(id_self);
  var elLayer=document.getElementById(id_layer);

  fActive = true;

  // 20030107: special for Opera7 which does not recognize TR- or TBODY-size
  // so: walk up to first TABLE tag. We can use the DIV-walker:
  if (bw.op7) {
    var parent = elSelf;
    while (parent.parentNode) {
      parent = parent.parentNode;
      if (parent.tagName == "TABLE") {
        var elSelfWidth = parent.offsetWidth;
        var elSelfHeight = parent.offsetHeight;
        break;
      }
    }
  } else {
    var elSelfWidth = elSelf.offsetWidth;
    var elSelfHeight = elSelf.offsetHeight;
  }

  // get cur menu DIV we're at: it's the next parent DIV. Works fine. Mac too.
  var parent = elSelf;
  while (parent.parentNode) {
    parent = parent.parentNode;
    if (parent.tagName == "DIV") {
      elemCurMenuAt = parent;
      break;
    }
  }

  // get cur level we're at: walk the level stack
  var onStack = false;
  curLevelAt++; //assume we go down
  for (var i = 1; i < stackMenu.length; i++) {
    if (stackMenu[i] == elemCurMenuAt) {
      // the current menu is on the stack
      onStack = true;
      curLevelAt = i;
      break;
    }
  }

  // happens only on level 1 change
  if (!onStack) {
    curLevelAt = 1;
    stackMenu[curLevelAt] = elemCurMenuAt;
  }

// removed 20020830: now done by CSS
/*  // cursor
  if (elemCurItem != elSelf) {
    if (elemCurItem) {elemCurItem.style.cursor = "Default";}
    elSelf.style.cursor = handcursor;
    // store
    elemCurItem = elSelf;
  }
*/  
  // colors
  // uncolor prev
  if (stackColored[curLevelAt]) colorTR(stackColored[curLevelAt],clrOut);
  // color this
  if (iStyle & cSkipColoring) {
    stackColored[curLevelAt] = null;
  } else {
    // remove persistent hottracking (feature skipped for Opera7, because it's not used anyway)
    if (!fHotTracking) {
      if (stackColored[curLevelAt-1]) stackColored[curLevelAt-1].style.backgroundColor = clrOut;
      if (stackColored[curLevelAt+1]) stackColored[curLevelAt+1].style.backgroundColor = clrOut;
    }
    colorTR(elSelf,clrOver);
    stackColored[curLevelAt] = elSelf;
  }

  // if we got an item change at the current level
  if (curLevelAt <= stackItem.length) {
    // note: if element is undefined, MacIE quits
    //       so we check explicitly and ensure it's defined
    if (typeof stackItem[curLevelAt] == "undefined") {
      stackItem[curLevelAt] = ""; //is set to elSelf below anyway
    }

    // note: moving cursor between TDs of one TR fires the TR mouseover event (all browsers)!
    //       (not relevant here because we compare TRs)
    if (stackItem[curLevelAt] != elSelf) {
      // cut the upper branch
      for (var i = stackMenu.length - 1; i > curLevelAt; i--) {
        stackMenu[i].style.visibility = "hidden";
        stackMenu.length--; //pop not supported by IE5-Mac
        stackItem.length--;
        // uncolor
        if (stackColored[i]) {colorTR(stackColored[i],clrOut); stackColored[i] = null;}
       }
      // push the new menu onto the stack
      if (elLayer) {
        stackMenu[curLevelAt+1] = elLayer; //push not supported by IE5-Mac
      }
    }
  }
  // update item stack
  stackItem[curLevelAt] = elSelf;

  /*debug*/
  //dmsg += "curLevelAt:" + curLevelAt + ", elemCurMenuAt:" + elemCurMenuAt.id + ", stackMenu[curLevelAt]:" + stackMenu[curLevelAt].id + ", stackMenu.length:" + stackMenu.length + "<br>";
  //dmsg += "Visible Menus: "; for (i = 1; i < stackMenu.length; i++) {dmsg += stackMenu[i].id + ", ";}; dmsg += "<br>";
  //dmsg += "Current Path: "; for (i = 1; i <= curLevelAt; i++) {dmsg += stackItem[i].id + ", ";}; dmsg +=  " stackItem.length:" + stackItem.length + "<br>";

	if (elLayer) {

    // page pos of current element
    if (bw.op7) {
      // Opera7 ignores TR, so we get the 1st child TD
      var idTD1 = elSelf.children[0];
      var offset = new getAbsoluteOffset(idTD1);
    } else {
      var offset = new getAbsoluteOffset(elSelf);
    }

    var winSize = new getBrowserWindowSize();

    /*debug*/
    //dmsg += "offset.x=" + offset.x + ", " + offset.sDepthX  + "<br>";
    //dmsg += "offset.y=" + offset.y + ", " + offset.sDepthY  + "<br>";
    //dmsg += "elSelf.offsetWidth=" + elSelf.offsetWidth + "<br>";
    //dmsg += "winSize.height=" + winSize.height + "<br>";
    //dmsg += "elLayer.offsetHeight=" + elLayer.offsetHeight + "<br>";


    // negotiate position
    // compensate the 1-pixel border of tables (class nav)
    var nav_paddingX = -1;
    var nav_paddingY = -1;
    if (iStyle & cPopDown) {
      x = offset.x + nav_paddingX;
      y = offset.y + nav_paddingY + elSelfHeight;
    } else {
      x = offset.x + nav_paddingX + elSelfWidth;
      y = offset.y + nav_paddingY;
    }

    // mind window right
    var overlapX = x + elLayer.offsetWidth - winSize.width - winSize.scrollX;

    if (overlapX > 0) {
      //popout left
      x = offset.x + nav_paddingX - 2 * nav_paddingX - elLayer.offsetWidth;
      //x -= (elSelfWidth + elLayer.offsetWidth) + 2 * nav_paddingX;
    }
    // mind window left
    if (x < winSize.scrollX) x = winSize.scrollX;
    // mind window bottom
    var overlapY = y + elLayer.offsetHeight - winSize.height - winSize.scrollY;
    if (overlapY > 0) {
      //move upwards from here
      y = offset.y - nav_paddingY + elSelfHeight - elLayer.offsetHeight;
      //old way:  y -= overlapY;    //move upwards, touch ground
    }
    // mind window top
    if (y < winSize.scrollY) y = winSize.scrollY; //but not too far

    // finally realize it
    elLayer.style.zIndex = 20; //ensure on top
    elLayer.style.left = x + bw.px;
    elLayer.style.top = y + bw.px;
    elLayer.style.visibility = "visible";

    //20020730: hide element
    showElement(false, idHideOnCollision, id_layer);

    /*debug*/
    //dmsg += "elLayer.left/top/width/height: " + elLayer.style.left +"/"+elLayer.style.top+"/"+elLayer.style.width+"/"+elLayer.style.height;

  } else {
    // no layer
  }

  //debugprint(dmsg);
}

function showElement(fShow, id_elem, id_layer) {
// 20020730: show/hide element (works around the combobox z-order bug)
// id_layer: ID of the menu layer that it about to pop out
// id_element: ID to hide (can be any HTML entity)
// fShow: set true to show element, false to hide
  var elLayer=document.getElementById(id_layer);
  var aid_elem=id_elem.split(",")  

  for (var i=0; i < aid_elem.length; i++) {
  
    var elElement=document.getElementById(aid_elem[i]);
    
    if (!elElement) continue;
    
    if (fShow == false) {
      // only if they overlap
      if (elementsOverlap(id_layer, aid_elem[i])) {
        // hide element
        elElement.style.visibility="hidden";
      }
    } else {
      // show element
      elElement.style.visibility="visible";  
    }  
  }  
}

function elementsOverlap(id1, id2) {
// (c) Donald 20020730
  var element1 = document.getElementById(id1);
  var element2 = document.getElementById(id2);
  var offset1 = new getAbsoluteOffset(element1);
  var offset2 = new getAbsoluteOffset(element2);
  var width1 = parseInt(element1.offsetWidth);
  var width2 = parseInt(element2.offsetWidth);
  var height1 = parseInt(element1.offsetHeight);
  var height2 = parseInt(element2.offsetHeight);
  // quit on certain non-overlaps
  if ((offset1.x < offset2.x) && (offset1.x + width1 < offset2.x)) {
    return false;
  }
  if ((offset2.x < offset1.x) && (offset2.x + width2 < offset1.x)) {
    return false;
  }
  if ((offset1.y < offset2.y) && (offset1.y + height1 < offset2.y)) {
    return false;
  }
  if ((offset2.y < offset1.y) && (offset2.y + height2 < offset1.y)) {
    return false;
  }
  // all checks passed
  return true;
}

