/*
  This code was written by Christian Lück <christian dot lueck at rub de>.
  Copyright 2010 Christian Lück

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this program.  If not, see
  <http://www.gnu.org/licenses/>.

 */

function Scroller()
{
    this.stepTime = 100; // time interval between steps in milliseconds
    
    // init some variables 
    this.direction = 1; // 1 for downwards, -1 for upwards
    this.origYPos = 0; // y-position before scrolling
    this.destYPos = 0; // y-position to scroll to
    this.nextYPos = 0; // y-position of the next step
    
    // a hack is needed since 'this' is not defined in an
    //event handler. Use 'me' instead of 'this'.
    me = this;
 
    //alert("Scroller initialized");
}

// returns the current y-position
Scroller.prototype.getCurrentYPos = function () 
{
    if (document.body && document.body.scrollTop)
	return document.body.scrollTop;
    if (document.documentElement && document.documentElement.scrollTop)
	return document.documentElement.scrollTop;
    if (window.pageYOffset)
	return window.pageYOffset;
    return 0;
}

// a function that is called after scolling is done
// TODO: not called yet!
Scroller.prototype.postScrollHook = function ()
{
}

// do the actual scrolling
// scroll to the nextYPos and calculate a new one by
Scroller.prototype.scrollWindow = function ()
{
    // scroll
    window.scrollTo(0, me.nextYPos);

    // calculate next y-position
    if ( !me.scrolledHalfTheWay )
	{
	    // caculate next y-position
	    nextYPos = me.origYPos + (me.direction * me.calcStepLength());
	    
	    if ( ( (nextYPos < me.halfTheWay) && (me.direction == 1) ) ||
		 ( (nextYPos > me.halfTheWay) && (me.direction == -1) ) )
		{
		    // increment step value
	    	    me.step++;
	    	    // use calculated step length
		    me.nextYPos = nextYPos;
		}
	    else
		{
		    me.scrolledHalfTheWay = true;
		    
		    // next y-position will be mirrored behind me.halfTheWay
		    me.nextYPos = me.nextYPos + (2 * ( me.halfTheWay - me.nextYPos ));
		}
	    
	}
    else
	{
	    me.step--;
	    me.nextYPos = me.destYPos - (me.direction * me.calcStepLength());
	    
	    if ( me.step == 0 )
		{
		    clearInterval(me.INTERVAL);
		    // scroll to the destination's y-position at the end
		    window.scrollTo(0, me.destYPos);
    
		}
	}
}

// the event handler function
Scroller.prototype.scrollHandler = function (e) 
{
    if (window.event) 
	{
	    target = window.event.srcElement;
	} 
    else if (e) 
	{
	    target = e.target;
	} 
    else return;

    // Make sure that the target is an element, not a text node
    // within an element
    if (target.nodeName.toLowerCase() != 'a') 
	{
	    target = target.parentNode;
	}

    // Paranoia; check this is an A tag
    if (target.nodeName.toLowerCase() != 'a') return;

    // Find the <a name> tag corresponding to this href
    // First strip off the hash (first character)
    anchor = target.hash.substr(1);
    // Now loop all A tags until we find one with that name
    var allLinks = document.getElementsByTagName('a');
    var destinationLink = null;
    for (var i=0; i<allLinks.length; i++) 
	{
	    var lnk = allLinks[i];
	    if (lnk.name && (lnk.name == anchor)) 
		{
		    destinationLink = lnk;
		    break;
		}
	}
    if (!destinationLink) destinationLink = document.getElementById(anchor);

    // If we didn't find a destination, give up and let the browser do
    // its thing
    if (!destinationLink) return true;

    // Find the destination's position
    me.destXPos = destinationLink.offsetLeft; 
    me.destYPos = destinationLink.offsetTop;
    var thisNode = destinationLink;
    while (thisNode.offsetParent && 
	   (thisNode.offsetParent != document.body)) 
	{
	    thisNode = thisNode.offsetParent;
	    me.destXPos += thisNode.offsetLeft;
	    me.destYPos += thisNode.offsetTop;
	}

    // Stop any current scrolling
    clearInterval(me.INTERVAL);

    me.origYPos = me.getCurrentYPos();

    // direction: 1 for scrolling down, -1 for up
    me.direction = (me.origYPos < me.destYPos)?1:-1;

    // set some values before scrolling is started
    me.scrolledHalfTheWay = false;
    me.halfTheWay = ( me.origYPos + me.destYPos ) / 2;
    me.step = 0; 

    me.preScrollHook();

    //alert("current y-position: " + me.origYPos + " destination's y-position: " + me.destYPos + " half the way: " + me.halfTheWay + " direction: " + me.direction);

    // do the scrolling
    me.INTERVAL = setInterval('me.scrollWindow()', me.stepTime);

    // And stop the actual click happening
    if (window.event) 
	{
	    window.event.cancelBubble = true;
	    window.event.returnValue = false;
	}
    if (e && e.preventDefault && e.stopPropagation) 
	{
	    e.preventDefault();
	    e.stopPropagation();
	}

    //me.postScrollHook(); // todo: put this somewhere else

}

// a function that is called before scrolling is started
Scroller.prototype.preScrollHook = function ()
{   
    // first step
    me.nextYPos = me.origYPos + me.calcStepLength();
}

Scroller.prototype.calcStepLength = function ()
{
    // scroll a fall
    return 1/2 * 9.81 * Math.pow(me.step, 2);
}

var fs = new Scroller(); // create an instance

function addEvent(elm, evType, fn, useCapture) 
{
    // addEvent and removeEvent
    // cross-browser event handling for IE5+,  NS6 and Mozilla
    // By Scott Andrew

    // if (elm.attachEvent) return true; // don't load if MSIE

    if (elm.addEventListener)
	{
	    elm.addEventListener(evType, fn, useCapture);
	    return true;
	} 
    else if (elm.attachEvent)
	{
	    var r = elm.attachEvent("on"+evType, fn);
	    return r;
	} 
    else 
	{
	    alert("Handler could not be removed");
	}
}

function fixAllLinks()
{
    // Get a list of all links in the page
    var allLinks = document.getElementsByTagName('a');
    // Walk through the list
    //alert(allLinks.length +  " links to be fixed");
    for ( var i=0; i<allLinks.length; i++ ) 
	{
	    var lnk = allLinks[i];
	    if ((lnk.href && lnk.href.indexOf('#') != -1) && 
		( (lnk.pathname == location.pathname) ||
		  ('/'+lnk.pathname == location.pathname) ) && 
		(lnk.search == location.search)) 
		{
		    // If the link is internal to the page (begins in #)
		    // then attach the smoothScroll function as an onclick
		    // event handler
		    addEvent(lnk, "click", fs.scrollHandler);
		}
	}
}

addEvent(window, "load", fixAllLinks);
