/* create a global namespace based on westcountywinds.org */

var org;
if(!org) org = {};
else if("object" != typeof org)
  throw new Error("global variable \"org\" already exists and is not an object");

if(!org.westcountywinds) org.westcountywinds = {};
else if("object" != typeof org.westcountywinds)
  throw new Error("global variable \"org.westcountywinds\" already exists and is not an object");

if(!org.westcountywinds.dyn) org.westcountywinds.dyn = {};
else if("object" != typeof org.westcountywinds.dyn)
  throw new Error("global variable \"org.westcountywinds.dyn\" already exists and is not an object");

// Internet Explorer...
if(!window.Node) {
    var Node = {
        ELEMENT_NODE: 1,
        ATTRIBUTE_NODE: 2,
        TEXT_NODE: 3,
        CDATA_SECTION_NODE: 4,
        PROCESSING_INSTRUCTION_NODE: 7,
        COMMENT_NODE: 8,
        DOCUMENT_NODE: 9,
        DOCUMENT_TYPE_NODE: 10,
        DOCUMENT_FRAGMENT_NODE: 11
    };
}

(function () { /* create functions and variables for dynamic page layout */

  // local variables available only within closure
  var pageContentDemand = 50; /* minimum percent of window height available for content */
  var els = {};               /* elements used by org.westcountywinds.dyn */
  var vhms_big = new Array(); /* stack for els that are now big    */
  var vhms_lil = new Array(); /* stack for els that are now little */
  var hashJump = false;

  var alertedIE = false;

  var getComputedStyle = window.getComputedStyle;
  if(!getComputedStyle) {
    getComputedStyle = (function(element, ignore) {
      return element.currentStyle;
    });
    // alert("Using IE-style computed style -- element.currentStyle");
  }

  var elementHeight = (function(element) {
    var style = getComputedStyle(element, null);
    if(style.display == "none") return 0;
    var result = 0;
    var attrlist = [
      "marginTop"   , "borderTopWidth"   , "paddingTop"   ,
      "marginBottom", "borderBottomWidth", "paddingBottom",
      "height"
    ];
    var attr;
    while(attr = attrlist.pop()) {
      var temp;
      result += (isNaN(temp = parseInt(style[attr])) ? 0 : temp)
    }
    if(result == 0) result = element.offsetHeight;
    return result;
  });

  function followSlug0 () {
    /* 
      the canonical response to resize, elements shrinking, 
      elements growing - never the wrong thing to do
     */
    els.divBody.style.top = els.divSlug0.offsetTop + "px";

    // now take care of the gimp...
    var re = /MSIE 6/;
    if(re.test(navigator.userAgent)) {
      if(!alertedIE) {
        // alert("Warning! Internet Explorer 6 detected.");
        alertedIE = true;
      }
      // not needed by sensible browsers; top and bottom should determine height
      var mT, bT, pT, H, pB, bB, mB;
      els.divBody.style.height =  (
        + els.divAll.offsetHeight 
        - els.divSlug0.offsetTop 
        - elementHeight(els.divFoot)
        - (isNaN(mT = parseInt(getComputedStyle(els.divBody, null).marginTop        )) ? 0 : mT)
        - (isNaN(bT = parseInt(getComputedStyle(els.divBody, null).borderTopWidth   )) ? 0 : bT)
        - (isNaN(pT = parseInt(getComputedStyle(els.divBody, null).paddingTop       )) ? 0 : pT)
        - (isNaN(pB = parseInt(getComputedStyle(els.divBody, null).paddingBottom    )) ? 0 : pB)
        - (isNaN(bB = parseInt(getComputedStyle(els.divBody, null).borderBottomWidth)) ? 0 : bB)
        - (isNaN(mB = parseInt(getComputedStyle(els.divBody, null).marginBottom     )) ? 0 : mB)
        ) + "px";
    }
  }

  var followWaiting = 0;
  var followCleared = 0;
  function followSlug0Sched(milliseconds) {
    if(followWaiting) {
      clearTimeout(followWaiting);
      followWaiting = null;
      followCleared++;
    }
    // followSlug0 scheduled for later invocation
    if(milliseconds == 0) {
      followSlug0();
    } else {
      followWaiting = setTimeout(followSlug0, milliseconds);
    }
  }

  var resizeWaiting = 0;
  var resizeCleared = 0;
  function onresizeSched(milliseconds) {
    if(resizeWaiting) {
      clearTimeout(resizeWaiting);
      resizeWaiting = null;
      resizeCleared++;
    }
    // onresizeDoNow scheduled for later invocation
    if(milliseconds == 0) {
      onresizeDoNow();
    } else {
      resizeWaiting = setTimeout(onresizeDoNow, milliseconds);
    }
  }
  function onresizeDelay () {
    /* this is the "onresize" handler; all it does is schedule the "real" handler for later */
    onresizeSched(500);
  }

  var resizeDoneNow = 0;
  function onresizeDoNow() {
    /*
      this is the real resize handler; it makes changes in response to 
      resizes, deciding whether to grow or shrink the shrinkable elements
     */
    resizeDoneNow++;
    demoMessage("resizing now, called \"" + resizeDoneNow + "\" times, cleared \"" + resizeCleared + "\" times");

    function _doMessage() {
      var message = "";
      if(vhms_big.length > 0)
        message +=
            "_doShrink(): pctOfAll is \"((" 
          + els.divBody.offsetHeight
          + " - "
          + els.PageContent.offsetTop
          + ") * 100)/"
          + els.divAll.offsetHeight
          + " = "
          + _pctOfAll(els.divBody.offsetHeight - els.PageContent.offsetTop)
      if(vhms_big.length > 0 && vhms_lil.length > 0)
        message += "\"<br />";
      if(vhms_lil.length > 0)
        message +=
            "_doGrow(): pct is \"(("
          +  els.divBody.offsetHeight
          + " - "
          + els.PageContent.offsetTop
          + " - " + vhms_lil[vhms_lil.length - 1].delta()
          + ") * 100)/"
          + els.divAll.offsetHeight
          + " = "
          + _pctOfAll(els.divBody.offsetHeight - els.PageContent.offsetTop - vhms_lil[vhms_lil.length - 1].delta())
          + "\"";
      demoMessage(message);
    }

    function _pctOfAll(height) {
      return ((100 * height)/els.divAll.offsetHeight);
    }

    function _doShrink() {
      _doMessage();
      var vhm;
      if(vhm = vhms_big.pop()) {
        if(pageContentDemand > _pctOfAll(els.divBody.offsetHeight - els.PageContent.offsetTop)) {
          // divBody demands more height
          vhm.make_lil();
          vhms_lil.push(vhm);
          return true;
        } else {
          // divBody has the height it wants
          vhms_big.push(vhm);
          return false;
        }
      } else {
        // no element to shrink
        return false;
      }
    }

    function _doGrow() {
      _doMessage();
      var vhm;
      if(vhm = vhms_lil.pop()) {
        if(pageContentDemand < _pctOfAll(els.divBody.offsetHeight - els.PageContent.offsetTop - vhm.delta())) {
          // this element needs less space than divBody has available; make it big
          vhm.make_big();
          vhms_big.push(vhm);
          return true;
        } else {
          // this element needs more space than divBody has available; keep it little
          vhms_lil.push(vhm);
          return false;
        }
      } else {
        // no element to grow
        return false;
      }
    }

    // make sure followSlug0 is called at least once for each resize
    var followed = false;
    while(_doShrink()) followed = true;
    while(_doGrow  ()) followed = true;
    if(!followed) followSlug0Sched(0);

    // on first call, scroll to any requested anchor (hash) after resizing
    if(!hashJump) {
      hashJump = true;
      if(window.location.hash && window.location.hash != "") {
        window.location.replace(window.location.hash)
      }
    }
  }

  org.westcountywinds.dyn.onload_dyn_layout = (function() {
    var id, ids;

    demoMessage("We're all loaded here.");

    // list id's of all elements to be used; find each element by id; save in els
    ids = [
      "divFoot", "divSlug1", "divHead", "divSlugR", "divSlugL", "divSide1", "divSide2", "divMenu", "divNews",
                                // these are the ones we adjust to make room
      "divBody", "PageContent", // these are what we're making room for...
      "divSlug0",               // automatically tracks the bottom of the top, as higher elements shrink or grow
      "divAll"                  // used to determine total available space
    ]
    while(id = ids.pop()) {
      var el = document.getElementById(id);
      if(el) {
        els[id] = el;
        // alert("onload found element \"" + id + "\"");
      } else {
        alert("onload couldn't find element \"" + id + "\"");
      }
    }

    // set up parameters for makeVHM (for shrinkable elements)
    var vhm_parm = {};

    vhm_parm["divSlug1"] = { css_attr: "display", big_val: "block", lil_val: "none" };
    vhm_parm["divSlugR"] = { css_attr: "display", big_val: "block", lil_val: "none" };
    vhm_parm["divFoot" ] = { css_attr: "display", big_val: "block", lil_val: "none" };
    vhm_parm["divHead" ] = { css_attr: "display", big_val: "block", lil_val: "none" };

    vhm_parm["divSlug1"].delta = elementHeight(els.divSlug1);
    vhm_parm["divSlugR"].delta = elementHeight(els.divSlugR);
    vhm_parm["divFoot" ].delta = elementHeight(els.divFoot);
    vhm_parm["divHead" ].delta = elementHeight(els.divHead) - elementHeight(els.divSlugR);

    vhm_parm["divSlugR"].adj_big = (function() { els.divSide1.appendChild (els.divSlugL); });
    vhm_parm["divSlugR"].adj_lil = (function() { els.divSide2.insertBefore(els.divSlugL, els.divSide2.firstChild); });

    vhm_parm["divHead" ].adj_big = (function() { els.divSide1.appendChild (els.divMenu ); });
    vhm_parm["divHead" ].adj_lil = (function() { els.divSide2.insertBefore(els.divMenu,  els.divSide2.firstChild); });

    vhm_parm["divFoot" ].adj_big = (function() { els.divBody.style.bottom = elementHeight(els.divFoot) + "px"; });
    vhm_parm["divFoot" ].adj_lil = (function() { els.divBody.style.bottom = "0px";                             });

    // list shrinkable elemements in order to be shrunk
    ids = [
        "divSlugR",      // note: SlugR should be shrunk before Head (which encloses it)
        "divFoot", 
        "divSlug1", 
        "divHead"
    ];
    while(id = ids.pop()) {          // processed reverse order of list
      // create VHM for each; push onto "big" list - first pushed, last shrunk
      vhms_big.push(makeVHM(id, vhm_parm[id]));
    }

    // set required element properties that differ from "default" layout
    els.divSlug0.style.display  = "block";
    els.divFoot .style.position = "absolute"
    els.divBody .style.position = "absolute";
    els.divFoot .style.bottom   = "0px";
    els.divBody .style.bottom   = elementHeight(els.divFoot) + "px";

    if(true) {
      followSlug0Sched(100);
      onresizeSched(200);
    } else {
      setTimeout(demo, 10000);
    }
  });

  /*
  create VHManagers for shrinkable elements, to be used by onresize handler

    vhm.make_big(): grow   element and adjust divBody, divPage
    vhm.make_lil(): shrink element and adjust divBody, divPage
    vhm.delta()   : return number of pixels gained or lost

  It would be nice to use getComputedValue, etc. to get
  full size, but I just want to get on with this, so will 
  enter constants copied from CSS.

  The arguments:
  -- id         the id of the element to be made big or lil (little)
  -- parm       an object with these attributes
   - delta      absolute value of number of pixels gained or lost
                Note: an integer, no "px" suffix
   - css_attr   the css style attribute to be changed (string)
   - big_val    the value to make element "big" (string, with unit suffix if needed)
   - lil_val    the value to make element "lil" (string, with unit suffix if needed)
   - adj_big    how to adjust divPage/divBody when element is made "big"
                if null    : use default adjustment function for vhm.adj_big
                if string  : js expression to be eval'd within function
                             definition wrapper in the local context
                if function: assigned to vhm.adj_big - won't be executed
                             in local context
   - adj_lil    how to adjust divPage/divBody when element is made "lil"

  */
  function makeVHM(id, parm) {
    var vhm = {}; // the result
    var element = els[id];

    vhm.make_big = (function () {
      var mesg = "growing \"" + element.id + "\"";
      var preH = element.offsetHeight;
      demoMessage(mesg);
      element.style[parm.css_attr] = parm.big_val;
      var delH = element.offsetHeight - preH;
      demoMessage(mesg + " by \"" + delH + "px\"")
      if(this.adj_big !== null) this.adj_big();
      followSlug0Sched(0); // must adjust now, before next big/lil test
    });

    vhm.make_lil = (function () {
      demoMessage("shrinking \"" + element.id + "\"");
      element.style[parm.css_attr] = parm.lil_val;
      if(this.adj_lil !== null) this.adj_lil();
      followSlug0Sched(0); // must adjust now, before next big/lil test
    });

    vhm.delta    = (function() {
      return parm.delta;
    });

    if(!parm.adj_big) {
      // nothing to do - followSlug0 suffices
      vhm.adj_big = null;
    } else if (typeof parm.adj_big == "function") {
      // use function passed in (will be evaluated in context of makeVHM's caller)
      vhm.adj_big = parm.adj_big;
    } else if (typeof parm.adj_big == "string")   {
      // define function here (will be evaluated in context of closure)
      vhm.adj_big = eval("(function() {" + parm.adj_big + ";})");
    }

    if(!parm.adj_lil) {
      // nothing to do - followSlug0 suffices
      vhm.adj_lil = null;
    } else if (typeof parm.adj_lil == "function") {
      // use function passed in (will be evaluated in context of makeVHM's caller)
      vhm.adj_lil = parm.adj_lil;
    } else if (typeof parm.adj_lil == "string")   {
      // define function here (will be evaluated in context of closure)
      vhm.adj_lil = eval("(function() {" + parm.adj_lil + ";})");
    }

    return vhm;
  }

  var demoShrinking = true;
  var demoLimit     = 30;
  function demo(milliseconds) {
    demoMessage("Hi, there.");
    //
    // shrinking or growing?
    if(vhms_lil.length == 0) demoShrinking = true;
    if(vhms_big.length == 0) demoShrinking = false;
    //
    if(demoShrinking) {
      vhm = vhms_big.pop();
      vhm.make_lil();
      vhms_lil.push(vhm);
    } else {
      vhm = vhms_lil.pop();
      vhm.make_big();
      vhms_big.push(vhm);
    }
    //
    if(--demoLimit > 0)
      setTimeout(demo, 5000);
  }
  function demoMessage(s) {
    return;
    var id;
    id = "NewsContent";
    id = "divName";
    document.getElementById(id).innerHTML = 
      "<p style='font-size: 12px; margin-top: 0;'>" + s + "</p>";
  }

  window.onresize = followSlug0;
  window.onresize = onresizeDelay;
  window.onresize = onresizeDoNow;
  // alert("that's all, folks!");

})(); /* end anonymous function defintion - invoke it! */

org.westcountywinds.dyn.onload_expandable_table = (function () {
  // alert("Initializing...");


  function elClassReplace(el, class_re, new_class) {
    var match_el = el.className ? el.className.match(class_re) : null;

    if(match_el) {
      el.className = el.className.replace(match_el[0],
          match_el[1] + new_class + match_el[match_el.length - 1]
        );
    }
    return match_el;
  }

  function elClassReplaceOrAdd(el, class_re, new_class) {

    // try replacement
    var match_el = elClassReplace(el, class_re, new_class);

    if(!match_el) {
      // replacement failed
      if(el.className) {
        // add new class
        el.className += " " + new_class;
      } else {
        // set new class
        el.className = new_class;
      }
    }
    return match_el;
  }

  var xrg_class_re = /(^|\s)expandableRowGroup(Big|Lil)?(\s|$)/;
  var toggle_class_re = /(^|\s)expandableToggle(Initially(Big|Lil))?(\s|$)/; 

  var list_td = document.getElementsByTagName("td");
  // alert("list_td length is \"" + list_td.length + "\"");

  for(var ix_td = 0; ix_td < list_td.length; ix_td++) {
    var td = list_td[ix_td];

    // * see if this td is an expandable toggle
    // * strip Initially(Big|Lil) if present
    // * match_td[3] remembers initial request for Big or Lil
    var match_td = elClassReplace(td, toggle_class_re, "expandableToggle");

    // skip unless this td is expandableToggle
    if(!match_td) continue;

    // find the closest ancestor tbody and table elements
    var tbody = null;
    var table = null;
    for(var el = td.parentNode; el != null; el = el.parentNode) {
      if(el.nodeType == Node.ELEMENT_NODE) {
        if(el.nodeName.toUpperCase() == "TBODY") {
          tbody = el;
        } else if (el.nodeName.toUpperCase() == "TABLE") {
          table = el;
          break;
        } 
      }
    }

    // set table className
    elClassReplaceOrAdd(table, /(^|\s)expandableTable(\s|$)/, "expandableTable");

    // set initial tbody className - depends on td className
    var xrg_class = "expandableRowGroup" + ((match_td[3] == "Lil") ? "Lil" : "Big");
    elClassReplaceOrAdd(tbody, xrg_class_re, xrg_class);

    // toggle td content is generated by CSS
    td.innerHTML = "";

    // create a closure so td.onclick remembers local functions and constants, and its target tbody
    td.onclick  = (
      function (tbody) {
        return (
          function () {
            var match_tbody = tbody.className.match(xrg_class_re);
            if(match_tbody) {
              var xrg_class = "expandableRowGroup" + 
                ((match_tbody[2] == "Big") ? "Lil" : "Big");
              elClassReplace(tbody, xrg_class_re, xrg_class);
            }
            return false;
          });
      })(tbody);

  }
});

window.onload = (function (previous) {
  return (function () {
    org.westcountywinds.dyn.onload_dyn_layout();
    org.westcountywinds.dyn.onload_expandable_table();
    if(previous) previous();
  });
})(window.onload);


