/* ************************************************************************* *
 * Scrolling Behaviour Implementation
 * ************************************************************************* */
 
function retrieveNameFromPath(path) {
// Return current file name as string.
// Value of path should have the last "/" or "\" just before the filename.

  // Clean path from bothering content.

  // At first, remove any search data
  var pos = path.indexOf("?")
  if (pos != -1)
    var path = path.slice(0, pos);
  
  // At second, remove all protocol prefixes.
  // Simultanously, determine whether path is relative or absolute.
  pos = path.lastIndexOf("://");
  if (pos == -1)
  
    if (path[0] == "/" || path[0] == "\\" || path.slice(1,2) == ":\\")
      var pathIsRelative = false;
    else
      var pathIsRelative = true;
      
  else {

    var pathIsRelative = false;
    path = path.slice(pos + 3);
  
  }
  
  // Finally, look up position of filename in cleaned path.
  var slashPos = path.lastIndexOf("/");
  if (slashPos == -1) slashPos = path.lastIndexOf("\\");

  // Return what is found.
  if (slashPos == -1)
    if (pathIsRelative) return path.toLowerCase();
    else return "";
    
  return path.slice(slashPos + 1).toLowerCase();
    
}

function getAnchorByHref(anchorSection, href) {

  // Retrieve all 'a' tags within anchorSection
  var arrAnchors = anchorSection.getElementsByTagName("a");

  // Retrieve numeric prefix as approximate position of anchor
  var secNumVal = parseInt(href); // Gather the first numeric charaters to a numeric value
  if (isNaN(secNumVal)) return getAnchorByHrefWithLinearSearchBackwards(arrAnchors, href);

  if (secNumVal <= arrAnchors.length) {
      
    // Retrieve numeric prefix from anchor at NORMAL position of wanted anchor
    var diffHref = arrAnchors[secNumVal - 1].getAttribute("href");
    var diffNumPrefix = parseInt(diffHref.slice(diffHref.lastIndexOf("/") + 1));
    
    // Provide a normalized value for backward search
    var secBackNormVal = secNumVal;
    
    // Compute search direction
    var sign = 0;
    if (secNumVal - diffNumPrefix < 0) sign = -1;
    else if (secNumVal - diffNumPrefix > 0) sign = +1;
    
  } else {
  
    // Provide a normalized value for backward search
    var secBackNormVal = arrAnchors.length + 1;
    
    // Set search direction
    var sign = -1;
    
  }

  // If 'sign == 0', most times anchor will be at position of its numerical number, so we
  // test it at first. But finally, for 'sign == 0' we cannot make any certain prediction
  // about where (and in which direction) anchor will lay.
  if (sign == 0) {
  
    // Start search with anchor at approximate position
    var pos = secNumVal - 1;
    var compHref = arrAnchors[pos].getAttribute("href");
    if (href == compHref.slice(compHref.lastIndexOf("/") + 1)) return arrAnchors[pos];
    
    // Else: Alternatingly test anchors BEHIND AND BEFORE approximate position
    // 
    // === Loop invariants ===
    // 1a)     forwNext <  (secNumVal - 1) + forwMax 
    //     <=> forwNext <  (secNumVal - 1) + (arrAnchors.length - (secNumVal - 1))
    //     <=> forwNext <  arrAnchors.length
    //     <=> forwNext <= arrAnchors.length - 1
    // 1b) forwNext >= (secNumVal - 1) + 1 = secNumVal
    // 2a)     backNext >  (secNumVal - 1) - backMax
    //     <=> backNext >  (secNumVal - 1) - secNumVal
    //     <=> backNext >  -1
    //     <=> backNext >= 0
    // 2b) backNext <= (secNumVal - 1) - 1 = secNumVal - 2
    //     (And: sign == 0 --> secNumVal - 2 <= arrAnchors.length - 2)
    // 
    //     == Backwards search ==
    //     (If sign == -1, maybe secNumVal - 2 > arrAnchors.length - 2.)
    //     For secBackNumVal = arrAnchors.length + 1:
    //     backNext <= (secBackNormVal - 1) - 1 = secBackNormVal - 2
    //     And: secNormVal - 2 = (arrAnchors.length + 1) - 2
    //        = arrAnchors.length - 1 <= arrAnchors.length - 1
    var backMax = secNumVal;
    var forwMax = arrAnchors.length - (secNumVal - 1) ;

    // We test for for-loop cancel condition WITHIN the loop, because then we have always,
    // except for the last test, one test term less than otherwise.
    for (var i = 1, j = 1; true; i++, j++) {
    
      if (i < forwMax) {
      
        var forwNext = (secNumVal - 1) + i;
        var compHref = arrAnchors[forwNext].getAttribute("href");
        if (href == compHref.slice(compHref.lastIndexOf("/") + 1)) return arrAnchors[forwNext];
        
      } else if (!(j < backMax)) break;
  
      if (j < backMax) {
      
        var backNext = (secNumVal - 1) - j;
        var compHref = arrAnchors[backNext].getAttribute("href");
        if (href == compHref.slice(compHref.lastIndexOf("/") + 1)) return arrAnchors[backNext];
        
      } else if (!(i < forwMax)) break;
    }
  }

  // else
  if (sign > 0) {
  
    // Start searching the anchors BEHIND approximate position
    var forwMax = arrAnchors.length - (secNumVal - 1) ;
    
    for (var i = 1; (i < forwMax); i++) {
    
      var forwNext = (secNumVal - 1) + i;
      var compHref = arrAnchors[forwNext].getAttribute("href");
      if (href == compHref.slice(compHref.lastIndexOf("/") + 1)) return arrAnchors[forwNext];
  
    }
  }
  
  // else
  if (sign < 0) {
    
    // Here we use secNormVal rather than secNumVal.
    // For the reason cf. Loop Invariants, 2b, above.
  
    // Start searching the anchors BEFORE approximate position
    var backMax = secBackNormVal;
    
    for (var j = 1; (j < backMax); j++) {
    
      var backNext = (secBackNormVal - 1) - j;
      var compHref = arrAnchors[backNext].getAttribute("href");
      if (href == compHref.slice(compHref.lastIndexOf("/") + 1)) return arrAnchors[backNext];
      
    }
  }
  
  return null;
  
}

function getAnchorByHrefWithLinearSearchBackwards(anchors, href) {

  //alert("Entering function getAnchorByHrefWithLinearSearchBackwards().");
  
  for (var next = anchors.length - 1; next > -1; next--) {
  
    var compHref = anchors[next].getAttribute("href");
    if (href == compHref.slice(compHref.lastIndexOf("/") + 1)) return anchors[next];
    
    // --> anchors[next].href always returns the *absolute* url, also when the string
    // which is used in the HTML doc for the href attrib is a relative (and shorter)
    // string. getAttribute("href") returns exactly what was written into the HTML file.
    
  }

  alert("Scrolling error in function getAnchorByHrefWithLinearSearchBackwards(): Scroll target not found!");
  return null;
  
}

function getDirectlyHeadingPTag(anchor) {

  currHeader = anchor.parentNode;
  
  /*
  confirm(
    currHeader.previousSibling & "\n"
    currHeader.previousSibling.nodeName & "\n"
    currHeader.previousSibling.previousSibling & "\n"
    currHeader.previousSibling.previousSibling.nodeName
  );
  */
  
  // Test, if newlines in code are represented as DOM nodes
  if (currHeader.previousSibling.nodeName == "#text") {
    
    testHeader = currHeader.previousSibling.previousSibling;
    while(testHeader) {
      
      if (testHeader.firstChild.nodeName != "A") {
        
        currHeader = testHeader;
        testHeader = currHeader.previousSibling.previousSibling;
        
      } else break;
    }
    
  } else {
  
    testHeader = currHeader.previousSibling;
    while(testHeader) {
    
      if (testHeader.firstChild.nodeName != "A") {
      
        currHeader = testHeader;
        testHeader = currHeader.previousSibling;
        
      } else break;
    }
    
  }
  
  return currHeader;
    
}

function scrollToCurrent(scrollSection, vAlign, padding) {
// Parameters are all optional!
// Values for scrollSection: HTML element, where the scrolling takes place,
// if omitted, function does nothing, but returns.
// Values for vAlign: "top", "middle" (default), "initial", "none"
// Values for padding: any number (float or integer) (default is 0)

  /* 
   * The following is already done in function init().
   * REACTIVATE it, if neccessary.
   * 
   * if (!scrollSection) return; // Nothing to do here anymore
   * if (vAlign == "none") return; // Nothing to do here anymore
   */
  
  if (vAlign == "initial") {
    // Do no align, but reposition element to its "initial" (=non-scrolled) position
    if (scrollSection.scrollTop) // If scrollTop is undefined or 0, there's nothing to do.
      scrollSection.scrollTop = 0;
    return;
  }

  // Use pathname, so nothing beyond any "?" in the URL will bother us
  var currName = retrieveNameFromPath(window.location.pathname);
  var targetAnchor = getAnchorByHref(scrollSection, currName);
  var scrollTarget = getDirectlyHeadingPTag(targetAnchor);
  
  if (scrollTarget) {
  
    var targetTop = scrollTarget.offsetTop;
    
    if (typeof(scrollSection.scrollTop) != 'undefined') { // scrollTop can be 0!
    
      if (!vAlign) vAlign = "middle";
      else if (!padding) padding = 0; // padding only needed, if vAlign != "middle"

      if (vAlign == "top") {
      
        // Vertically align element at top with padding (if not undefined)
        scrollSection.scrollTop = Math.floor(targetTop - padding);
        
      } else if (vAlign == "middle") {
      
        // Vertically align element in the middle, no padding applied
        var scrollSectionHalfHeight = scrollSection.clientHeight / 2;
        var scrollTargetHalfHeight = scrollTarget.parentNode.clientHeight / 2;
        scrollSection.scrollTop = Math.floor(targetTop - scrollSectionHalfHeight + scrollTargetHalfHeight);
        
      }
    }
  }
}

/* ************************************************************************* *
 * Dynamic Height Adjustment
 * ************************************************************************* */
 
function getClientHeight() {

  if (document.documentElement.clientHeight) return document.documentElement.clientHeight; // FF, in MSIE the only defined one
  if (window.innerHeight) return window.innerHeight; // FF, not MSIE
  return 495 + 108; // 16px for possible horz. scrollbar is not needed (at least in FF/MSIE)
  
}

/* 
 * Event handler for the resize event
 */

function scroll_navi_onResize() {

  // 108 = 44 + 44 + 20
  //     = header space + footer space + top paddings of divs
  var newCentralHeight = (getClientHeight() - 108) + "px";
  document.getElementById("content").style.height = newCentralHeight;
  document.getElementById("leftCol").style.height = newCentralHeight;
  
}

/* ************************************************************************* *
 * Init function to be invoked in body tag's onload attribute
 * ************************************************************************* */
 
function scroll_navi_init(naviId, vAlign, alignPadding) {

  /* 
   * Settings for resizing events
   */

  // Force Firefox to hide scrollbars
  var bodyTag = document.getElementsByTagName("body")[0];
  var e;
  if (bodyTag.style.overflow != undefined
  && navigator.appName != "Microsoft Internet Explorer") 
    try { bodyTag.style.overflow = "hidden ! important"; }
    catch(e) {};

  window.onresize = scroll_navi_onResize;
  window.onresize();
  
  /* 
   * Code for scrolling behaviour
   */

  if (!naviId) return; // Nothing to do here anymore
  if (vAlign == "none") return; // Nothing to do here anymore

  var navi = document.getElementById(naviId);
  if (!navi) return; // Nothing to do here anymore

  scrollToCurrent(navi, vAlign, alignPadding);

}


