var titlePane,   //The Title
    loadPane,    //The Pane used for loading msg
    msgPane,     //The Pane used to dosplay messages
    menu,        //The Navigator object
    menuPane,    //The Navigation Pane
    contentPane, //The Content Pane
    copyPane;    //The Copyright Pane

var defaultMsg = "Watch this space for messages";
var separator = "/";
var root      = "";
var scrollTimer = null;

if(!is.supported) alert("W A R N I N G! Your browser is not supported by this site." +
			"I cannot guarantee that things will work as they should. " +
			"Consider downloading either Mozilla >=1.4 or Internet Explorer >= 6");

var windowWidth; var windowHeight;
function ieHack() {
    windowWidth  = getInsideWindowWidth();
    windowHeight = getInsideWindowHeight();
    positionLayers();
}
//Called when document loads
function onLoad() { 
  if(is.ie) {
    windowWidth  = getInsideWindowWidth();
    windowHeight = getInsideWindowHeight();
  } 
  loadPane  = new VisualElement(getReferenceToNode("loadPane"));
  titlePane = new VisualElement(getReferenceToNode("titlePane"));
  msgPane = new VisualElement(getReferenceToNode("msgPane"));
  msgPane.setInnerHTML(defaultMsg);
  menu = new Menu(topLevel);
  menuPane = menu.chrome;
  contentPane = new VisualElement(getReferenceToNode("contentPane"));

  if(is.ie) window.onresize = ieHack;
  else window.onresize = positionLayers;
  
  positionLayers();
  
  loadPane.setVisible(false); 
  titlePane.setVisible(true);
  msgPane.setVisible(true);
  menuPane.setVisible(true);
  contentPane.setVisible(true);

  disableDragSelectionOn(getReferenceToNode("body"));
  window.defaultStatus = "kovidgoyal.net - Done";
}

function positionLayers() {
  var width = (is.ie) ? windowWidth : getInsideWindowWidth();
  var height = (is.ie) ? windowHeight : getInsideWindowHeight();
  titlePane.centerX();
  titlePane.setTop(0);
  msgPane.setWidth(titlePane.getWidth());
  msgPane.setTop(height - msgPane.getHeight()-5);
  msgPane.centerX();
  menuPane.setSize(width*0.27,
			       msgPane.getTop()-titlePane.getBottom()-6);
  menuPane.setLeft(this.titlePane.getLeft());
  menuPane.setTop(this.titlePane.getBottom()+3);
  menu.positionLayers();
  contentPane.setLeft(menuPane.getRight() + 5);
  contentPane.setTop(menuPane.getTop());
  contentPane.setSize(titlePane.getRight() - contentPane.getLeft(),
		      menuPane.getHeight());
}	


function Menu(topLevel) {
  this.topLevel = topLevel;
  this.nodes    = topLevel;
  this.createChrome();
}

function reload() {
  load(contentPane.node.src, contentPane.node.src);
}
function info() {
  load("information about kovidgoyal.net", "about.html");
}

function help() {
  load("help on using kovidgoyal.net", "help.html");
}

function activateButton() {
  var node = (this.childNodes.length > 0) ? this.childNodes[0] : this;
  node.style.background = "#e2e2ff";
}

function deActivateButton() {
  var node = (this.childNodes.length > 0) ? this.childNodes[0] : this;
  node.style.background = "transparent";
  if(this.getAttribute("class") == "scrollButton") stopScroll();
}
function pressButton() {
  var node = (this.childNodes.length > 0) ? this.childNodes[0] : this;
  node.style.borderStyle = "inset";
}
function raiseButton() {
  var node = (this.childNodes.length > 0) ? this.childNodes[0] : this;
  node.style.borderStyle = "outset";
}
function startScroll() { 
  if(this.id == "upScroll") {
    if(menu.contentView.getOffsetTop() < 0) scroll("up");
    else {
      showMsg("Top Reached", "red");
      setTimeout("showMsg('"+defaultMsg+"', '#eeeeee')", 2000);
    }
  } else {
    if(menu.contentView.getOffsetBottom() > menu.viewPane.getHeight())
      scroll("dn");
    else {
      showMsg("Bottom Reached", "red");
      setTimeout("showMsg('"+defaultMsg+"', '#eeeeee')", 2000);
    }
  }  
}

function scroll(dir) {
  if(dir == "dn") {
    menu.contentView.setOffsetTop(menu.contentView.getOffsetTop()-menu.scrollAmt);
    if(menu.contentView.getOffsetBottom() < menu.viewPane.getHeight()) {
      menu.contentView.setOffsetBottom(menu.viewPane.getHeight());
      clearTimeout(scrollTimer);
      scrollTimer = null;      
    } else {
      scrollTimer = setTimeout("scroll('dn')", menu.scrollInterval);
    }
  } else {
    menu.contentView.setOffsetTop(menu.contentView.getOffsetTop()+menu.scrollAmt);
    if(menu.contentView.getOffsetTop() > 0) {
      menu.contentView.setOffsetTop(0);      
      clearTimeout(scrollTimer);
      scrollTimer = null;
    } else {
      scrollTimer = setTimeout("scroll('up')", menu.scrollInterval);
    }
  }
  menu.slider.setPosition(((-1)*menu.contentView.getOffsetTop())/
			  (menu.contentView.getHeight()-menu.viewPane.getHeight()));
}

function scrollTo(frac) {
  menu.contentView.setOffsetTop((-1)*frac*(menu.contentView.getHeight()-menu.viewPane.getHeight()));
}

function stopScroll() {
  clearTimeout(scrollTimer);
  scrollTimer = null;
}

Menu.prototype.createChrome = function(width, height) { 
  this.chrome = new VisualElement(document.createElement("DIV"));
  this.chrome.setVisible(false);
  this.chrome.setOverflow("hidden");
  this.chrome.setBorder("solid 1px black");
  this.scrollAmt = 7;
  this.scrollInterval = 50;
  getReferenceToNode("body").appendChild(this.chrome.node);

  this.topPane = new VisualElement(document.createElement("DIV"), false);
  this.topPane.node.style.borderBottom = "solid 1px black";
  this.chrome.node.appendChild(this.topPane.node);
  this.buttonPane = new VisualElement(document.createElement("DIV"));
  this.buttonPane.setHeight((is.ie)?32:26);
  this.buttonPane.node.style.paddingTop = "8px";
  this.buttonPane.setOverflow("hidden");
  this.topPane.node.appendChild(this.buttonPane.node);
  this.buttons = new Array();
  for(c = 0; c < 5; c++) {
    if(is.ie) {
       this.buttons[c] = document.createElement("IMG");
       this.buttons[c].style.verticalAlign = "middle";
       this.buttons[c].setAttribute("class", "button");
       this.buttons[c].style.border = "1px outset blue";
       this.buttons[c].style.cursor = "hand";
       this.buttons[c].setAttribute("height", "22");
       this.buttons[c].setAttribute("width", "22");
    } else {
       this.buttons[c] = document.createElement("A");
       this.buttons[c].appendChild(document.createElement("IMG"));
       this.buttons[c].childNodes[0].setAttribute("class", "button");
       this.buttons[c].childNodes[0].setAttribute("height", "22");
       this.buttons[c].childNodes[0].setAttribute("width", "22");
       this.buttons[c].childNodes[0].style.verticalAlign = "middle";
       this.buttons[c].href        = "javascript: clickMe()";
    } 
    this.buttons[c].setAttribute("height", "22");
    this.buttons[c].setAttribute("width", "22");
    this.buttons[c].onmouseover = activateButton;
    this.buttons[c].onmouseout  = deActivateButton;
    this.buttons[c].onmousedown = pressButton;
    this.buttons[c].onmouseup   = raiseButton;
    
    this.buttonPane.node.appendChild(this.buttons[c]);    
  }
  if(is.ie) this.buttons[3].src = "images/info.gif";
  else this.buttons[3].childNodes[0].src = "images/info.png";
  this.buttons[3].onclick = info;
  if(is.ie) this.buttons[0].src = "images/up.gif";
  else this.buttons[0].childNodes[0].src = "images/up.png";
  this.buttons[0].onclick = upOneLevel;
  if(is.ie) this.buttons[2].src = "images/gohome.gif";
  else this.buttons[2].childNodes[0].src = "images/gohome.png";
  this.buttons[2].onclick = resetToTop;
  if(is.ie) this.buttons[1].src = "images/reload.gif";
  else this.buttons[1].childNodes[0].src = "images/reload.png";
  this.buttons[1].onclick = reload;
  if(is.ie) this.buttons[4].src = "images/help.gif";
  else this.buttons[4].childNodes[0].src = "images/help.png";
  this.buttons[4].onclick = help;

  this.IN = new VisualElement(document.createElement("DIV"));
  this.IN.setID("IN");
  this.IN.setCursor("default");
  this.IN.setInnerHTML(this.pathTo(null));
  this.topPane.node.appendChild(this.IN.node);

  this.scrollPane = new VisualElement(document.createElement("DIV"));
  this.scrollPane.setWidth(16);
  this.scrollPane.setVisible(false);
  this.chrome.node.appendChild(this.scrollPane.node);
  var ext = (is.ie) ? "gif" : "png";
  var upB = "<img id='upScroll' class='scrollButton' src='images/uparrow."+ext+"' style='cursor: hand'/>";
  var dnB = "<img id='dnScroll' class='scrollButton' src='images/downarrow."+ext+"' style='cursor: hand'/>";
  this.scrollPane.setInnerHTML(upB + dnB);
  this.scrollPane.node.childNodes[0].onmouseover = activateButton;
  this.scrollPane.node.childNodes[0].onmouseout  = deActivateButton;
  this.scrollPane.node.childNodes[0].onmousedown = startScroll;
  this.scrollPane.node.childNodes[0].onmouseup   = stopScroll;
  this.scrollPane.node.childNodes[1].onmouseover = activateButton;
  this.scrollPane.node.childNodes[1].onmouseout  = deActivateButton;
  this.scrollPane.node.childNodes[1].onmousedown = startScroll;
  this.scrollPane.node.childNodes[1].onmouseup   = stopScroll;
  this.upButton = new VisualElement(this.scrollPane.node.childNodes[0]);
  this.dnButton = new VisualElement(this.scrollPane.node.childNodes[1]);
  var fe = new VisualElement(document.createElement("IMG"));
  fe.node.src = "images/slider."+ext;
  fe.setSize(15,15);
  fe.setBorder("solid 1px #e2e2ff");
  //fe.setSize((is.ie)?15:16, (is.ie)?15:16);
  this.scrollPane.node.appendChild(fe.node);
  this.slider = new Slider(fe, VERTICAL_SLIDER, 0.0, 0, 10, 10, 0);
  this.slider.addUpdateListener(this);
  
  this.viewPane = new VisualElement(document.createElement("DIV"));
  this.viewPane.setID("viewPane");
  this.viewPane.setOverflow("hidden");
  this.chrome.node.appendChild(this.viewPane.node);
  this.contentView = new VisualElement(document.createElement("UL"));
  this.contentView.node.style.paddingTop = "0.7em";
  this.viewPane.node.appendChild(this.contentView.node);
  this.populateViewPane();
}

Menu.prototype.positionLayers = function() { 
  this.IN.setOffsetTop(3);
  this.buttonPane.setOffsetTop(this.IN.getHeight());
  var width = this.chrome.getWidth()-2;
  var pad = Math.floor((width - 5*24 - 6)/4);
  if(pad > 8) pad = 8;
  if(pad < 1) pad = 1;
  this.buttonPane.setWidth(24*5 + 4*pad);
  for(c = 0; c < 4; c++) {
    this.buttons[c].style.marginRight = pad + "px";
  }  
  this.topPane.setWidth(width);
  this.topPane.setHeight(this.buttonPane.getOffsetBottom()+6);
  this.IN.centerXIn(this.topPane);
  this.buttonPane.centerXIn(this.topPane);

  this.viewPane.setWidth(this.topPane.getWidth());
  this.viewPane.setOffsetTop(this.topPane.getHeight());
  this.viewPane.setOffsetLeft(0);
  this.viewPane.setHeight(this.chrome.getHeight() - this.viewPane.getOffsetTop());
  this.contentView.setOffsetTop(0);
  
  this.scrollPane.setOffsetRight(this.topPane.getWidth());
  this.scrollPane.setTop(this.viewPane.getTop());
  this.scrollPane.setHeight(this.viewPane.getHeight());
  this.upButton.setOffsetTop(0); this.upButton.setOffsetLeft(0);
  this.dnButton.setOffsetBottom(this.scrollPane.getHeight());
  this.upButton.setOffsetLeft(0);
  this.slider.moveTo(this.scrollPane.getLeft(), this.upButton.getBottom());
  this.slider.resizeTo(this.scrollPane.getWidth(),
		       this.scrollPane.getHeight()-this.dnButton.getHeight() -
		       this.upButton.getHeight());
		  
  if(this.chrome.isVisible() && this.contentView.getHeight() > this.viewPane.getHeight())
    this.showScrollPane();
  else this.hideScrollPane();
}

Menu.prototype.onSliderUpdate = function() {
  scrollTo(this.slider.getPosition());
}

Menu.prototype.hideScrollPane = function() {
  this.viewPane.setWidth(this.topPane.getWidth());
  this.scrollPane.setVisible(false);
  this.slider.setVisible(false);
} 
Menu.prototype.showScrollPane = function() {
  this.viewPane.setWidth(this.viewPane.getWidth() - this.scrollPane.getWidth());
  this.scrollPane.setVisible(true);
  this.slider.setVisible(true);
}

//Dummy functions for statusbar
function showContent() {}
function clickMe() {}

Menu.prototype.populateViewPane = function() {
  var firstRun = this.contentView.getInnerHTML().length == 0;
  this.contentView.setInnerHTML("");
  for(c = 0; c < this.nodes.length; c++) {
    var li = new VisualElement(document.createElement("li"), false);
    var html = "<a class='liLink' href='javascript: showContent()'" +
      "onclick='menuClicked(this)'" + 
      " id='menuNode_" + this.nodes[c].hash + "' onmouseover='menuHighlight(this)'" +
      " onmouseout='menuRestore(this)'>" +
      this.nodes[c].toString() +
      "</a>";
    li.setInnerHTML(html);
    this.contentView.node.appendChild(li.node);
  }
  if(!firstRun) this.positionLayers(); //needed to get scrollpane to display
                         //alternate method doesn't work
}


Menu.prototype.handleClick = function(hash) {
  var node = this.hashToNode(hash);
  if(node.url) {
    load(node.toString(), node.url);
  }
  if(!node.isLeaf) {
    this.showPath(node);
    this.nodes = node.nodes;
    highlightedNode = null;
    clickedNode = null;
    this.populateViewPane();    
  }
}

Menu.prototype.showPath = function(node) {
  this.IN.setInnerHTML(this.pathTo(node));
  this.IN.centerXIn(this.topPane);
}

Menu.prototype.pathTo = function(node) {
  if(node == null) return (root)?root:separator;
  var parent = node;
  var path = "";
  while(parent) {
    path = separator + parent.toString() + path;
    parent = parent.parent;
  }
  return root + path;
}

function resetToTop() {
  menu.nodes = menu.topLevel;
  menu.showPath(null);
  load("Blurb", "blurb.html");
  clickedNode = null;
  highlightedNode = null;
  menu.populateViewPane();
}

function upOneLevel() {
  if(menu.nodes == menu.topLevel) return;
  var node = menu.nodes[0].parent.parent;
  var name = "";
  var url  = "blurb.html";
  var what = "Blurb";
  if(node == null) {
    menu.nodes = menu.topLevel;    
  } else { 
    menu.nodes = node.nodes;
    if(node.url) {
      url = node.url;
      what = node.toString();
      name = what;
    }
  }
  load(what, url);
  menu.showPath(node);
  highlightedNode = null;
  clickedNode = null;
  menu.populateViewPane();    
}


function load(what, url) {
  if(url != null) {
    showMsg("Loading " + what + "...", "#ffbbbb");
    contentPane.node.src = url;
    
  } 
}

function loadingDone() {    
  if(msgPane != null && msgPane.getInnerHTML().indexOf("Loading") > -1) {
    showMsg(defaultMsg, "#eeeeee");
  }
}

Menu.prototype.hashToNode = function(hash) {  
  var node = null;
  var nodes = this.topLevel;
  var src = hash;
  var id;
  while(true) {
    var sub = src.substr(0, src.indexOf(":"));
    id = parseInt(sub);
    node = nodes[id];
    nodes = node.nodes;
    src = src.substr(src.indexOf(":")+1);
    if(src.length < 1) break;
  }
  return node;
}


var menuItemCounter = 0;
function MenuItem(parent, shortDesc, longDesc, url, isLeaf) {
  this.parent = parent;  
  if(parent) {
    if(parent.isLeaf) return;
    this.hash   = parent.hash + parent.menuItemCounter++ + ":";
  } else this.hash = menuItemCounter++ + ":";
  this.isLeaf = (isLeaf != null) ? isLeaf : true;
  if(!isLeaf) {
    this.nodes = new Array();
    this.menuItemCounter = 0;
  }
  if(parent) parent.nodes.add(this);
  this.shortDesc = shortDesc;
  this.about = longDesc;
  this.url = url;
}

MenuItem.prototype.toString = function() { return this.shortDesc; }
MenuItem.prototype.length   = function() { return this.nodes.length; }
MenuItem.prototype.equals   = function(m) { return this.hash == m.hash; }

MenuItem.prototype.addLeaf = function(shortDesc, longDesc, url) {
  new MenuItem(this, shortDesc, longDesc, url, true);
}
MenuItem.prototype.addBranch = function(shortDesc, longDesc, url) {
  new MenuItem(this, shortDesc, longDesc, url, false);
}

function showMsg(msg, color) {
  msgPane.setInnerHTML(msg);
  msgPane.setForegroundColor(color);
}
  
/////////////////////////Menu Highlight System///////////////////////////
var highlightedNode = null;
var clickedNode     = null;
function menuHighlight(node) {
  if(node != highlightedNode) {
    if(highlightedNode != null) {
      normNode(highlightedNode);
      showMsg(defaultMsg, "#eeeeee");
    }
    node.style.color = "red";
    node.style.letterSpacing = "0.3em";
    var node = menu.hashToNode(node.id.substr(node.id.indexOf("_")+1));
    var msg = node.about; 
    if(!node.about) msg = "No information about " + node.toString() + " available";
    showMsg(msg, "#aaffaa");
    highlightedNode = node;
  }
}

function menuRestore(node) {
  if(node != clickedNode) {
    normNode(node);
  } else clickNode(node);
  highlightedNode = null;
  showMsg(defaultMsg, "#eeeeee");
}

function menuClicked(node) {
  if(clickedNode) normNode(clickedNode);
  clickedNode = node;
  clickNode(node);
  menu.handleClick(node.id.substr(node.id.indexOf("_")+1));
}
function clickNode(node) {
  node.style.color = "green";
  node.style.letterSpacing = "";
}
function normNode(node) {
  node.style.color = "blue";
  node.style.letterSpacing = "";
}
/////////////////////////Temp stuff//////////////////////////////////////
var topLevel = new Array();
topLevel[0]  = new MenuItem(null, "Me, Myself and I", "Worms eye view", "content/memyi.html", false);
topLevel[1]  = new MenuItem(null, "Poems", "My poetry", "", false);
topLevel[2]  = new MenuItem(null, "D<i>ynamic</i> HTML",
			    "My Dynamic HTML work (The Visual Document API, widgets, etc.)",
			    "content/dhtml/index.html", false);
topLevel[3]  = new MenuItem(null, "Code Nuggets",
			    "Small pieces of code to ease life on a GNU/Linux system.",
			    "content/nuggets/nuggets.xml", false);
topLevel[4] = new MenuItem(null, "Stories", "Stories I've written now and again",
			   "content/stories.html", false);
topLevel[5] = new MenuItem(null, "Essays", "As it says", "content/essays.html", false);
topLevel[6] = new MenuItem(null, "Philosophy", "An example of how children think",
			   "content/phil.html", false);
topLevel[0].addLeaf("Rank and Serial Number", "The Bare Bones", "content/memyi.html#RankAndSerialNumber");
topLevel[0].addLeaf("Interests", "As It Says", "content/memyi.html#interests");
topLevel[0].addLeaf("Contact Me", "Addresses", "content/memyi.html#contactMe");

topLevel[1].addBranch("Sketches", "Man is a hairy beast; impossible to entrap in a syllable cage",
		    "content/sketches.html");
topLevel[1].addBranch("Miscellanuous", "Various poems",
		    "content/misc-poems.html");
topLevel[2].addLeaf("Tester", "Visual Document API Tester", "content/dhtml/Tester/index.html");
topLevel[2].addLeaf("Basic Widgets", "Image preloader, Slider, Vertical Menu and Progress Bar",
		    "content/dhtml/Widgets/BasicSet/index.html");
topLevel[2].addLeaf("Advanced Widgets", "Music Player Widget", "content/dhtml/Widgets/AdvancedSet/index.html" );

topLevel[3].addLeaf("LaTeX Makefile", "Automate processing for LaTeX documents",
		    "content/nuggets/nuggets.xml#latexMakefile");
topLevel[3].addLeaf("Recent Files Menu (XEmacs)", "Add a recent files menu to XEmacs",
		    "content/nuggets/nuggets.xml#rfLib");
topLevel[3].addLeaf("Temp File Deletion", "Bash script to automatically delete temp files",
		    "content/nuggets/nuggets.xml#tempScript");
topLevel[3].addLeaf("Network Print Script", "Bash script to print files over a network",
		    "content/nuggets/nuggets.xml#printScript");
topLevel[3].addLeaf("Website Update Script", "Bash script to automatically update a website",
		    "content/nuggets/nuggets.xml#webUpdScript");
topLevel[3].addLeaf("Unexecing Files", "Perl script to remove executable permissions from files in specified directories",
		    "content/nuggets/nuggets.xml#unexecScript");
topLevel[3].addLeaf("XEmacs Customization", "My XEmacs customizations",
		    "content/nuggets/nuggets.xml#xemacsCustom");
topLevel[3].addLeaf("Clip Download Script", "Download clips automatically",
		    "content/nuggets/nuggets.xml#kowalScript");
topLevel[4].addLeaf("A Lament", "Short Story: A Lament", "content/stories.html#aLament");
topLevel[4].addLeaf("The Conversation", "Dialogue: The Conversation", "content/stories.html#theConversation");

topLevel[5].addLeaf("My Computer Lives...", "SF and philosophy...", "content/essays.html#compLives");
topLevel[5].addLeaf("If I had the Time to Stare", "Whining", "content/essays.html#timeToStare");
topLevel[5].addLeaf("Outsiders", "More whining ;)", "content/essays.html#outsiders");

topLevel[6].addLeaf("How and Why Everything Pretends to Work", "As it says", "content/phil.html#howAndWhy");
topLevel[6].addLeaf("The Future", "As it says", "content/phil.html#theFuture");
topLevel[6].addLeaf("Technology", "As it says", "content/phil.html#technology");

topLevel[1].nodes[0].addLeaf("Wordsmith", "", "content/sketches.html#wordsmithu0429");
topLevel[1].nodes[0].addLeaf("The Learned Lispius", "", "content/sketches.html#tllu8943");
topLevel[1].nodes[0].addLeaf("The Mole in a Hole", "", "content/sketches.html#tmiahu5403");
topLevel[1].nodes[0].addLeaf("Loner", "", "content/sketches.html#loneru45933");
topLevel[1].nodes[0].addLeaf("Colours", "", "content/sketches.html#coloursu40230");
topLevel[1].nodes[0].addLeaf("Wedding Bells", "", "content/sketches.html#wbu54084");
topLevel[1].nodes[0].addLeaf("The Sage of Sorbonne", "", "content/sketches.html#tsosu540045");
topLevel[1].nodes[0].addLeaf("Mumbasa", "", "content/sketches.html#mumbasau504509");
topLevel[1].nodes[0].addLeaf("The Matchless Society", "", "content/sketches.html#tmsu59045");
topLevel[1].nodes[0].addLeaf("The Leaking Barrel", "", "content/sketches.html#tlbu85994");
topLevel[1].nodes[0].addLeaf("Wisdom", "", "content/sketches.html#wisdomu4938394");
topLevel[1].nodes[0].addLeaf("Courage", "", "content/sketches.html#courageu6059");
topLevel[1].nodes[0].addLeaf("Bitterness", "", "content/sketches.html#bitternessu54963793");
topLevel[1].nodes[0].addLeaf("Research", "", "content/sketches.html#researcha47694");
topLevel[1].nodes[0].addLeaf("Reflections", "", "content/sketches.html#reflecg44694");
topLevel[1].nodes[0].addLeaf("Sand", "", "content/sketches.html#Sandhjg44694");

topLevel[1].nodes[1].addLeaf("Chimes", "", "content/misc-poems.html#chimesu1");
topLevel[1].nodes[1].addLeaf("The Mouse and The Man", "", "content/misc-poems.html#tmatmu2");
topLevel[1].nodes[1].addLeaf("Change", "", "content/misc-poems.html#changeu3");
topLevel[1].nodes[1].addLeaf("Whirligigs", "", "content/misc-poems.html#whirlu4");
topLevel[1].nodes[1].addLeaf("Ocean Song", "", "content/misc-poems.html#osu5");
topLevel[1].nodes[1].addLeaf("Untitled", "", "content/misc-poems.html#untu9");
topLevel[1].nodes[1].addLeaf("Statute Tales", "", "content/misc-poems.html#stu78");
topLevel[1].nodes[1].addLeaf("Coronation Day", "", "content/misc-poems.html#cdu67");
topLevel[1].nodes[1].addLeaf("Gum Arabic", "", "content/misc-poems.html#ga674");
topLevel[1].nodes[1].addLeaf("Climb", "", "content/misc-poems.html#climbu984");
topLevel[1].nodes[1].addLeaf("Search", "", "content/misc-poems.html#searchf2001");
topLevel[1].nodes[1].addLeaf("Cipher", "", "content/misc-poems.html#cipherap2001");
topLevel[1].nodes[1].addLeaf("Progress", "", "content/misc-poems.html#progmay2001");
topLevel[1].nodes[1].addLeaf("Pretense", "", "content/misc-poems.html#pretensejune2001");
topLevel[1].nodes[1].addLeaf("A Poem", "", "content/misc-poems.html#apaug2001");
topLevel[1].nodes[1].addLeaf("Conflict", "", "content/misc-poems.html#confjan2002");
topLevel[1].nodes[1].addLeaf("The Plunge", "", "content/misc-poems.html#thepfeb2002");
topLevel[1].nodes[1].addLeaf("Group Theory", "", "content/misc-poems.html#grptheoryjan2004");




//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////The Slider Widget
//////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MAX_ZINDEX = 1000000-1;
HORIZONTAL_SLIDER = -1;
VERTICAL_SLIDER = 1;
Slider.prototype.sliderCounter = 0;
Slider.prototype.sliderListenerList = new EventDispatcherList();
//frontEnd - The VisualElement that represents the sliding button.
//type - can be either HORIZONTAL_SLIDER or VERTICAL_SLIDER
//initialPosition - fraction from 0.0 to 1.0
//top, right, bottom, left - co-ordinates of the sliding rectangle in the BODY co-ord system
function Slider(frontEnd, type, initialPosition, top, right, bottom, left) {
  if(typeof frontEnd.getBorderRightWidth != "function")
    fireError("Slider Consructor|Parameter 'frontEnd' is not a VisualElement.");
  if(type != HORIZONTAL_SLIDER && type != VERTICAL_SLIDER)
    fireError("Slider Constructor| Parameter 'type' must be either " + HORIZONTAL_SLIDER + " or " + VERTICAL_SLIDER);
  if(!(initialPosition >= 0 && initialPosition <= 1))
    fireError("Slider Constructor|Parameter 'initialPosition' is invalid.");
  if(typeof top != "number" || typeof right != "number" || typeof bottom != "number" || typeof left != "number")
    fireError("Slider Construstor|Invalid set of position parameters for sliding rectangle");
  this.frontEnd = frontEnd;
  this.initFrontEnd();
  this.type = type;
  this.initialPosition = initialPosition;
  this.changeSlidingRectangle(top, right, bottom, left);
  this.createDragShield();
  this.setListenerCode();
  this.calculateBuffer();
  this.allowsDrag = false;
  this.activateListeners = new EventListenerList();
  this.updateListeners = new EventListenerList();
  this.deactivateListeners = new EventListenerList();
}

Slider.prototype.initFrontEnd = function() {
  this.frontEnd.node.onmousedown = this.fireActivateEvent;
  this.frontEnd.setCursor("hand");
  //Needed for getWidth and getHeight to work in changeSliding Rect
  //in above it become a child of sliding rect
  getReferenceToNode("BODY").appendChild(this.frontEnd.node); 
  disableDragSelectionOn(this.frontEnd.node);
  this.frontEnd.setVisible(false);  
}

Slider.prototype.setVisible = function(which) { this.frontEnd.setVisible(which); }

Slider.prototype.calculateBuffer = function() {
  if(this.type == HORIZONTAL_SLIDER) this.buffer = Math.round(this.frontEnd.getWidth() / 2);
  else this.buffer = Math.round(this.frontEnd.getHeight()/2);
}

Slider.prototype.changeSlidingRectangle = function(top, right, bottom, left) {
  var frac; 
  this.right = (this.type == HORIZONTAL_SLIDER) ? right - this.frontEnd.getWidth() : right;
  this.bottom = (this.type == VERTICAL_SLIDER) ? bottom - this.frontEnd.getHeight() : bottom;
  this.top = top;
  this.left = left;
  this.length = (this.type == HORIZONTAL_SLIDER) ? this.right - this.left : this.bottom - this.top;
  
  if(this.slidingRectangle == null) {
    frac = this.initialPosition;
    var sr = document.createElement("DIV");
    getReferenceToNode("BODY").appendChild(sr);
    this.slidingRectangle = new VisualElement(sr, true);
    sr.onmousemove = this.fireUpdateEvent;
    sr.onmouseup = this.fireDeActivateEvent;
    this.slidingRectangle.setZIndex(MAX_ZINDEX - 200);
    this.slidingRectangle.setVisible(true);
    disableDragSelectionOn(this.slidingRectangle.node);
    //appendChild automaticallt removes node from BODY
    this.slidingRectangle.node.appendChild(this.frontEnd.node);
  } else frac = this.getPosition();

  this.slidingRectangle.setLocation(this.left, this.top);
  this.slidingRectangle.setSize(right - left, bottom - top);	     
}

//This function returns a fraction from 0.0 (top) to 1.0 (bottom) reflecting the current position
//of the slider.
Slider.prototype.getPosition = function() {
  var num = this.initialPosition; var den = 1;
  if(this.type == HORIZONTAL_SLIDER) {
    num = this.frontEnd.getLeft() - this.left;
    den = this.length;
  } else {
    num = this.frontEnd.getTop() - this.top;
    den = this.length;
  }
  return num/den;
}

Slider.prototype.setListenerCode = function() {
  this.listenerCode = ++Slider.prototype.sliderCounter;
  this.slidingRectangle.setID("SlidingRectangle_" + this.listenerCode);
  this.dragShield.setID("SliderDragShield_" + this.listenerCode);
  this.frontEnd.setID("SliderFrontEnd_" + this.listenerCode);
  Slider.prototype.sliderListenerList.addDispatcher(this);
}

Slider.prototype.createDragShield = function() {
  var ds = document.createElement("DIV");
  var body = new VisualElement(document.getElementsByTagName("BODY").item(0), false, false);
  body.node.appendChild(ds);
  this.dragShield = new VisualElement(ds, true, false);
  this.dragShield.setLocation(0, 0);
  this.dragShield.setSize(body.getWidth(), body.getHeight());
  this.dragShield.setZIndex(this.slidingRectangle.getZIndex()-1);
  this.dragShield.setCursor("default");
  this.dragShield.setBackground("url('lkl')");
  this.dragShield.setVisible(false);
  ds.onmouseup = this.fireDeActivateEvent;
}
//listener must be an object that implements the listener.onSliderActivate method.
Slider.prototype.addActivateListener = function(listener) {
  if(typeof listener.onSliderActivate != "function") { showAPIError(listener + " does not implement the onSliderActivate method."); return; }
  this.activateListeners.addListener(listener);
}
//listener must be an object that implements the listener.onSliderUpdate method.
Slider.prototype.addUpdateListener = function(listener) {
  if(typeof listener.onSliderUpdate != "function") {showAPIError(listener + " does not implement the onSliderUpdate method."); return; }
  this.updateListeners.addListener(listener);
}
//listener must be an object that implements the listener.onSliderDeActivate method.
Slider.prototype.addDeActivateListener = function(listener) {
  if(typeof listener.onSliderDeActivate != "function") {showAPIError(listener + " does not implement the onSliderDeActivate method."); return; }
  this.deactivateListeners.addListener(listener);
}

Slider.prototype.removeActivateListener = function(listener) {
  this.activateListeners.removeListener(listener);
}
Slider.prototype.removeDeActivateListener = function(listener) {
  this.deactivateListeners.removeListener(listener);
}
Slider.prototype.removeUpdateListener = function(listener) {
  this.updateListeners.removeListener(listener);
}

Slider.prototype.fireActivateEvent = function(evt) {
  evt = new InterfaceEvent(evt);
  var src = evt.getSourceNode().id;
  var slider = Slider.prototype.sliderListenerList.getDispatcherFor(src.substring(src.indexOf("_") + 1, src.length));
  if(slider == null) return;
  evt.stopBubble();
  slider.dragShield.setVisible(true);
  slider.allowsDrag = true;
  var listeners = slider.activateListeners.getListeners();
  for(c = 0; c < listeners.length; c++) listeners[c].onSliderActivate(slider.frontEnd);
}

Slider.prototype.fireUpdateEvent = function(evt) {
  evt = new InterfaceEvent(evt);
  var src = evt.getSourceNode().id;
  var slider = Slider.prototype.sliderListenerList.getDispatcherFor(src.substring(src.indexOf("_") + 1, src.length));
  if(slider == null || !slider.allowsDrag) return;
  evt.stopBubble();
  if(slider.type == HORIZONTAL_SLIDER) {
    var x = evt.getEventX() - slider.left;
    if(x < slider.buffer) x = slider.buffer;
    if(x > (slider.length + slider.buffer)) x = slider.length + slider.buffer;
    slider.frontEnd.setOffsetLeft(x - slider.buffer);
  } else {
    var y = evt.getEventY() - slider.top;
    if(y < (slider.buffer)) y = slider.buffer;
    if(y > (slider.length + slider.buffer)) y = slider.length + slider.buffer;
    slider.frontEnd.setOffsetTop(y - slider.buffer);
  }
  var listeners = slider.updateListeners.getListeners();
  for(c = 0; c < listeners.length; c++) listeners[c].onSliderUpdate(slider.frontEnd, slider.getPosition());
}

Slider.prototype.fireDeActivateEvent = function(evt) {
  evt = new InterfaceEvent(evt);
  var src = evt.getSourceNode().id;
  var slider = Slider.prototype.sliderListenerList.getDispatcherFor(src.substring(src.indexOf("_") + 1, src.length));
  if(slider == null) return;
  slider.dragShield.setVisible(false);
  slider.allowsDrag = false;
  var listeners = slider.deactivateListeners.getListeners();
  for(c = 0; c < listeners.length; c++) listeners[c].onSliderDeActivate(slider.frontEnd);
}

//This function sets the position of the slider without calling onupdate.
//A value of 0.0 sets it to top and 1.0 to bottom.
Slider.prototype.setPosition = function(fraction) {
  if(this.type == HORIZONTAL_SLIDER) {
    var newX = this.length * fraction;
    this.frontEnd.setOffsetLeft(newX);
  } else {
    var newY = this.length * fraction;
    this.frontEnd.setOffsetTop(newY);
  }
}

Slider.prototype.moveTo = function(left, top) {
  this.changeSlidingRectangle(top, left + this.slidingRectangle.getWidth(), top + this.slidingRectangle.getHeight(), left);
}

Slider.prototype.resizeBy = function(widthFactor, heightFactor) {
  var oldHeight = this.slidingRectangle.getHeight();
  var oldWidth = this.slidingRectangle.getWidth();
  this.resizeTo((oldWidth * widthFactor), (oldHeight * heightFactor));
}

Slider.prototype.resizeTo = function(width, height) {
  this.changeSlidingRectangle(this.top, this.left + width, this.top + height, this.left);
}

Slider.prototype.equals = function(obj) {
  return (obj == this);
}

