////
//// Development Tools
////

// Window containing the tools
var tools;

// Array of all IDs of elements having IDs.
//
var ids = new Array();

// Hash from group name to: hash from member name to document element.
// The element has ID=<group>__<member>.
//
var groups = new Object();



function tw(text) {
  tools.document.writeln(text);
}

// Walks the node element and all its child nodes, calling the
// visitor function on each.  Recurs into all elements.  Traversal
// is parent first then children.
function walk(node, visitor) {
  if (node.tagName) {
    visitor(node);
    for (var child=node.firstChild; child; child=child.nextSibling) {
      walk(child, visitor);
    }
  }
}


function checkID(elt) {
  if (elt.id) {
    var id = elt.id;
    // elt.title = id;
    ids.push(id);
    var match = id.match(/^(.*)__(.*)$/);
    if (match) {
      var group = match[1];
      var item = match[2];
      if (!groups[group]) {
	groups[group] = new Object();
      }
      groups[group][item] = elt;
    }
  }
}


// Currently called on load of document in devmode.  That doesn't necessarily
// work though on account of popup blocking.
//
function initTools_old() {
  walk(document.body, checkID);

  tools = window.open
    ("", "tools", "width=300, height=400, status, resizable, scrollbars"
     +"left=0,screenX=0,top=0,screenY=0");
  if (!tools) {
    return;
  }
  tw('<html>');
  tw('<head>');
  tw('</head>');
  tw('<body>');
  tw('<form name=controller>');
  writeGroups();
  tw('<h3>Displayable</h3>');
  tw('<ul>');
  writeDisplayables();
  tw('</ul>');
  tw('<h3>Other IDs</h3>');
  tw('<ul>');
  writeIndivs();
  tw('</ul>');
  tw('</form>');
  tw('</body>');
  tw('</html>');
  tools.document.close();
  tools.getStyle = getStyle;
  tools.computedStyle = computedStyle;
  tools.actualStyle = actualStyle;
}


function writeGroups() {
  tw('<h3>Groups</h3>');
  for (var name in groups) {
    tw('<b>'+name+'</b><br>');
    var alts = groups[name];
    for (var member in alts) {
      tw('<input type=radio name="'+name+'" value="'+member+'"'
	 +(getStyle(name+"__"+member, "display")!="none" ? " checked" : "")
	 +' onclick="opener.chooseDisplay(this)">'+member+'<br>');
    }
  }
}


function writeDisplayables() {
  for (var i=0; i<ids.length; i++) {
    var id = ids[i];
    if (id.match(/__/) || id=="innerFrame")
      continue;
    var elt = document.getElementById(id);
    var display = actualStyle(elt).display;
    if (display!="none")
      continue;
    tw('<li>'+id+': <a id="'+id
       +'" href="javascript:opener.toggle(\''+id+'\')">'
       +display+'</a>');
  }
}


function writeIndivs() {
  for (var i=0; i<ids.length; i++) {
    var id = ids[i];
    if (id.match(/__/))
      continue;
    var elt = document.getElementById(id);
    var display = actualStyle(elt).display;
    if (display=="none")
      continue;
    tw('<li>'+id+': <a id="'+id
       +'" href="javascript:opener.toggle(\''+id+'\')"'
       +'>'+display+'</a>');
  }
}


// Let the given radio button determine a group member to display.
// The button will have the group name as its name and the member
// name as its value.
//
function chooseDisplay(input) {
  var group = groups[input.name];
  var elt = group[input.value];
  var display = "block";
  for (var key in group) {
    var e = group[key];
    if (e!=elt) {
      var d = getStyle(e, "display");
      if (d!="none") {
	display = d;
      }
      e.style.display = "none";
    }
  }
  elt.style.display = display;
}


function displayOn(elt) {
  
}


function toggle(id) {
  toggleDisplay(id);
  var a = tools.document.getElementById(id);
  setText(a, tools.computedStyle(id, "display"));
}


function toggleDisplay(id) {
  var elt = document.getElementById(id);
  var display = getStyle(elt, "display");
  if (display!="none" && !getAttr(elt, "ondisplay"))
    setAttr(elt, "ondisplay", display);
  if (display=="none") {
    var saved = getAttr(elt, "ondisplay");
    if (!saved) {
      // Very simplified calculation of preferred display style
      if (elt.tagName=="SPAN")
	saved = "inline";
      else
	saved = "block";
    }
    setAttr(elt, "style.display", saved);
  } else {
    setAttr(elt, "style.display", "none");
  }
}


function actualStyles(elt) {
  return window.getComputedStyle
    ? getComputedStyle(elt, null)
    : elt.currentStyle;
}

function computedStyle(target, style) {
  var elt = element(target);
  return actualStyles(elt)[style];
}


// This needs to use borderTopStyle, borderLeftStyle, etc..
// specifically rather than borderStyle.  This code partially
// works, but does not get the actual current style(s).
// (Does note work.)
function showBorder(input) {
  var id = input.id;
  var elt = element(id);
  var current = getStyle(elt, "borderStyle");
  elt.saveBorderStyle = current;
  elt.style.borderStyle = "dashed";
}


// See comments on showBorder.
//
function unShowBorder(input) {
  var id = input.id;
  var elt = element(id);
  if (elt.saveBorderStyle) {
    elt.borderStyle = elt.saveBorderStyle;
  } else {
    // elt.style.removeProperty("borderStyle");
    elt.style.borderStyle = "none";
  }
}


// Opens a window that attempts to make itself into a clone of its opener.
// seems to work in Mozilla 1.7 except for form state.  In IE 6, can work
// for the document body -- including forms state, but does not permit
// setting innerHTML of head content.
//
function cloneMe() {
  var e = document.documentElement.cloneNode(true);
  removeScripts(e);
  var clone = window.open("", "clone");
  clone.document.write(e.innerHTML);
  clone.document.close();
  return clone;
}

// Walks the document tree, removing all script elements.
function removeScripts(e) {
  var next;
  for (var child=e.firstChild; child; child=next) {
    next = child.nextSibling;
    if (child.tagName=="SCRIPT") {
      e.removeChild(child);
    } else if (child.tagName) {
      removeScripts(child);
    }
  }
}


// For development

function evalAndAlert(expr) {
  var value;
  try {
    value = eval(expr);
  } catch(e) {
    alert((e.constructor.name ? e.constructor.name+": " : "")+e.message);
    return false;
  }
  var svalue = window.description
    ? window.description(value, true)
    : ""+value;
  // var svalue = ""+value;
  if (window.isKHTML || svalue.match(/\n/) || svalue.length>80) {
    alert(svalue);
  } else {
    window.defaultStatus = "Value: "+svalue;
  }
  // False to use as an event handler to suppress submission.
  return false;
}


// Initializes tools.  Currently sets title attributes to reflect
// the ID of each element.
function initTools() {
  var counter = 0;
  var a = document.getElementsByTagName("*");
  for (var i=0; i<a.length; i++) {
    var e = a[i];
    if (e.getAttributeNode("iw_title_orig")) {
      counter++;
      continue;
    }
    var title = e.getAttribute("title") || "";
    var id = e.getAttribute("id");
    if (id) {
      e.setAttribute("title", "id="+id+(title?" "+title:""));
      e.setAttribute("iw_title_orig", title);
    } else {
      var name = e.getAttribute("name");
      if (name) {
	e.setAttribute("title", "name="+name+" "+title);
	e.setAttribute("iw_title_orig", title);
      }
    }
  }
}

function timer(fn, args, stats) {
  var start = new Date().getTime();
  var v = fn.apply(args);
  var end = new Date().getTime();
  var duration = end - start;
  stats.time += duration;
  stats.count++;
  return v;
}


