/**
* History/Remote - jQuery plugin for enabling history support and bookmarking
* @requires jQuery v1.0.3
*
* http://stilbuero.de/jquery/history/
*
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Version: 0.2.3
*/

(function($) { // block scope

  /**
  * Initialize the history manager. Subsequent calls will not result in additional history state change 
  * listeners. Should be called soonest when the DOM is ready, because in IE an iframe needs to be added
  * to the body to enable history support.
  *
  * @example $.ajaxHistory.initialize();
  *
  * @param Function callback A single function that will be executed in case there is no fragment
  *                          identifier in the URL, for example after navigating back to the initial
  *                          state. Use to restore such an initial application state.
  *                          Optional. If specified it will overwrite the default action of 
  *                          emptying all containers that are used to load content into.
  * @type undefined
  *
  * @name $.ajaxHistory.initialize()
  * @cat Plugins/History
  * @author Klaus Hartl/klaus.hartl@stilbuero.de
  */
  $.ajaxHistory = new function() {

    var RESET_EVENT = 'historyReset';

    var _currentHash = location.hash;
    var _intervalId = null;
    var _observeHistory; // define outside if/else required by Opera

    this.update = function() { }; // empty function body for graceful degradation

    // create custom event for state reset
    var _defaultReset = function() {
      $('.remote-output').empty();
    };
    $(document).bind(RESET_EVENT, _defaultReset);

    // TODO fix for Safari 3
    // if ($.browser.msie)
    // else if hash != _currentHash
    // else check history length

    if ($.browser.msie) {

      var _historyIframe, initialized = false; // for IE

      // add hidden iframe
      $(function() {
        _historyIframe = $('<iframe style="display: none;"></iframe>').appendTo(document.body).get(0);
        var iframe = _historyIframe.contentWindow.document;
        // create initial history entry
        iframe.open();
        iframe.close();
        if (_currentHash && _currentHash != '#') {
          iframe.location.hash = _currentHash.replace('#', '');
        }
      });

      this.update = function(hash) {
        _currentHash = hash;
        var iframe = _historyIframe.contentWindow.document;
        iframe.open();
        iframe.close();
        iframe.location.hash = hash.replace('#', '');
      };

      _observeHistory = function() {

        var iframe = _historyIframe.contentWindow.document;
        var iframeHash = iframe.location.hash;
        //alert(iframeHash);
        //alert(_currentHash);
        if (iframeHash != _currentHash) {
          _currentHash = iframeHash;
          if (iframeHash && iframeHash != '#') {
            //alert("clicking...");
            // order does matter, set location.hash after triggering the click...
            //$('a[@href$="' + iframeHash + '"]').click();
            var ieAnchor = iframeHash.replace("#", "_");
            $('#' + ieAnchor).click();
            //alert("clicked...");
            location.hash = iframeHash;
          } else if (initialized) {
            //alert("inside else");
            location.hash = '';
            $(document).trigger(RESET_EVENT);
          }
        }
        else {
          
        }
        initialized = true;
      };

    } else if ($.browser.mozilla || $.browser.opera) {

      this.update = function(hash) {
        _currentHash = hash;
      };

      _observeHistory = function() {
        //alert("back / forward");
        if (location.hash) {
          if (_currentHash != location.hash) {
            _currentHash = location.hash;

            var anchorId = _currentHash;
            anchorId = anchorId.replace("#", "_");
            //alert("trigger fired for - " + anchorId);
            $("#" + anchorId).trigger('click');

            //alert("back forward triggering !");
            //alert("current hash" + _currentHash);
            //$('a[@href$="' + _currentHash + '"]').trigger('click');
            //$('a[@href$="' + _currentHash + '"]').click();
          }
        } else if (_currentHash) {
          _currentHash = '';
          $(document).trigger(RESET_EVENT);
        }
      };

    } else if ($.browser.safari) {

      var _backStack, _forwardStack, _addHistory; // for Safari

      // etablish back/forward stacks
      $(function() {
        _backStack = [];
        _backStack.length = history.length;
        _forwardStack = [];

      });
      var isFirst = false, initialized = false;
      _addHistory = function(hash) {
        _backStack.push(hash);
        _forwardStack.length = 0; // clear forwardStack (true click occured)
        isFirst = false;
      };

      this.update = function(hash) {
        _currentHash = hash;
        _addHistory(_currentHash);
      };

      _observeHistory = function() {
        var historyDelta = history.length - _backStack.length;
        if (historyDelta) { // back or forward button has been pushed
          //alert("back/forward");
          isFirst = false;
          if (historyDelta < 0) { // back button has been pushed
            // move items to forward stack
            for (var i = 0; i < Math.abs(historyDelta); i++) _forwardStack.unshift(_backStack.pop());
          } else { // forward button has been pushed
            // move items to back stack
            for (var i = 0; i < historyDelta; i++) _backStack.push(_forwardStack.shift());
          }
          var cachedHash = _backStack[_backStack.length - 1];
          var safariAnchor = cachedHash.replace("#", "_");
          //alert("clicked " + safariAnchor);
          //$("#" + safariAnchor).click();
          //$('a[@href$="' + cachedHash + '"]').click();
          _currentHash = location.hash;
        } else if (_backStack[_backStack.length - 1] == undefined && !isFirst) {
          // back button has been pushed to beginning and URL already pointed to hash (e.g. a bookmark)
          // document.URL doesn't change in Safari
          if (document.URL.indexOf('#') >= 0) {
            //alert("bad one !");
            $('#_' + document.URL.split('#')[1]).click();
            //$('a[@href$="' + '#' + document.URL.split('#')[1] + '"]').click();
          } else if (initialized) {
            $(document).trigger(RESET_EVENT);
          }
          isFirst = true;
        }
        initialized = true;
      };

    }

    this.initialize = function(callback) {
      // custom callback to reset app state (no hash in url)
      if (typeof callback == 'function') {
        $(document).unbind(RESET_EVENT, _defaultReset).bind(RESET_EVENT, callback);
      }
      // look for hash in current URL (not Safari)
      if (location.hash && typeof _addHistory == 'undefined') {
        //alert("click triggering");
        var anchorId = location.hash;
        anchorId = anchorId.replace("#", "_");
        //alert("trigger fired for - " + anchorId);
        $("#" + anchorId).trigger('click');
        //$("#" + anchorId).click();
        //$('a[@href$="' + location.hash + '"]').trigger('click');
        //$('a[@href$="' + location.hash + '"]').trigger('click');
        //alert("click triggered");
      }
      // start observer
      if (_observeHistory && _intervalId == null) {
        _intervalId = setInterval(_observeHistory, 200); // Safari needs at least 200 ms
      }
    };

  };

  /**
  * Implement Ajax driven links in a completely unobtrusive and accessible manner (also known as "Hijax")
  * with support for the browser's back/forward navigation buttons and bookmarking.
  *
  * The link's href attribute gets altered to a fragment identifier, such as "#remote-1", so that the browser's
  * URL gets updated on each click, whereas the former value of that attribute is used to load content via
  * XmlHttpRequest from and update the specified element. If no target element is found, a new div element will be
  * created and appended to the body to load the content into. The link informs the history manager of the 
  * state change on click and adds an entry to the browser's history.
  *
  * jQuery's Ajax implementation adds a custom request header of the form "X-Requested-With: XmlHttpRequest"
  * to any Ajax request so that the called page can distinguish between a standard and an Ajax (XmlHttpRequest)
  * request.
  *
  * @example $('a.remote').remote('#output');
  * @before <a class="remote" href="/path/to/content.html">Update</a>
  * @result <a class="remote" href="#remote-1">Update</a>
  * @desc Alter a link of the class "remote" to an Ajax-enhanced link and let it load content from
  *       "/path/to/content.html" via XmlHttpRequest into an element with the id "output".
  * @example $('a.remote').remote('#output', {hashPrefix: 'chapter'});
  * @before <a class="remote" href="/path/to/content.html">Update</a>
  * @result <a class="remote" href="#chapter-1">Update</a>
  * @desc Alter a link of the class "remote" to an Ajax-enhanced link and let it load content from
  *       "/path/to/content.html" via XmlHttpRequest into an element with the id "output".
  *
  * @param String expr A string containing a CSS selector or basic XPath specifying the element to load
  *                    content into via XmlHttpRequest.
  * @param Object settings An object literal containing key/value pairs to provide optional settings.
  * @option String hashPrefix A String that is used for constructing the hash the link's href attribute
  *                           gets altered to, such as "#remote-1". Default value: "remote-".
  * @param Function callback A single function that will be executed when the request is complete. 
  * @type jQuery
  *
  * @name remote
  * @cat Plugins/Remote
  * @author Klaus Hartl/klaus.hartl@stilbuero.de
  */

  /**
  * Implement Ajax driven links in a completely unobtrusive and accessible manner (also known as "Hijax")
  * with support for the browser's back/forward navigation buttons and bookmarking.
  *
  * The link's href attribute gets altered to a fragment identifier, such as "#remote-1", so that the browser's
  * URL gets updated on each click, whereas the former value of that attribute is used to load content via
  * XmlHttpRequest from and update the specified element. If no target element is found, a new div element will be
  * created and appended to the body to load the content into. The link informs the history manager of the 
  * state change on click and adds an entry to the browser's history.
  *
  * jQuery's Ajax implementation adds a custom request header of the form "X-Requested-With: XmlHttpRequest"
  * to any Ajax request so that the called page can distinguish between a standard and an Ajax (XmlHttpRequest)
  * request.
  *
  * @example $('a.remote').remote( $('#output > div')[0] );
  * @before <a class="remote" href="/path/to/content.html">Update</a>
  * @result <a class="remote" href="#remote-1">Update</a>
  * @desc Alter a link of the class "remote" to an Ajax-enhanced link and let it load content from
  *       "/path/to/content.html" via XmlHttpRequest into an element with the id "output".
  * @example $('a.remote').remote('#output', {hashPrefix: 'chapter'});
  * @before <a class="remote" href="/path/to/content.html">Update</a>
  * @result <a class="remote" href="#chapter-1">Update</a>
  * @desc Alter a link of the class "remote" to an Ajax-enhanced link and let it load content from
  *       "/path/to/content.html" via XmlHttpRequest into an element with the id "output".
  *
  * @param Element elem A DOM element to load content into via XmlHttpRequest.
  * @param Object settings An object literal containing key/value pairs to provide optional settings.
  * @option String hashPrefix A String that is used for constructing the hash the link's href attribute
  *                           gets altered to, such as "#remote-1". Default value: "remote-".
  * @param Function callback A single function that will be executed when the request is complete. 
  * @type jQuery
  *
  * @name remote
  * @cat Plugins/Remote
  * @author Klaus Hartl/klaus.hartl@stilbuero.de
  */
  $.fn.remote = function(output, settings, callback) {

    callback = callback || function() { };
    if (typeof settings == 'function') { // shift arguments
      callback = settings;
    }

    settings = $.extend({
      hashPrefix: 'remote-'
    }, settings || {});

    var target = $(output).size() && $(output) || $('<div></div>').appendTo('body');
    target.addClass('remote-output');

    return this.each(function(i) {
      var href = this.href, hash = '#' + (this.title && this.title.replace(/\s/g, '_') || settings.hashPrefix + (i + 1)),
            a = this;
      var anchorId = $(this).attr("id");
      this.href = hash;
      $(this).click(function(e) {
        //alert("clicked");
        // lock target to prevent double loading in Firefox
        if (!target['locked']) {
          // add to history only if true click occured, not a triggered click
          if (e.clientX) {
            $.ajaxHistory.update(hash);
          }
          //          target.load(href, function() {
          //            target['locked'] = null;
          //            callback.apply(a);
          //          });
        }
      });
    });

  };

  /**
  * Provides the ability to use the back/forward navigation buttons in a DHTML application.
  * A change of the application state is reflected by a change of the URL fragment identifier.
  *
  * The link's href attribute needs to point to a fragment identifier within the same resource,
  * although that fragment id does not need to exist. On click the link changes the URL fragment
  * identifier, informs the history manager of the state change and adds an entry to the browser's
  * history.
  *
  * @param Function callback A single function that will be executed as the click handler of the 
  *                          matched element. It will be executed on click (adding an entry to 
  *                          the history) as well as in case the history manager needs to trigger 
  *                          it depending on the value of the URL fragment identifier, e.g. if its 
  *                          current value matches the href attribute of the matched element.
  *                           
  * @type jQuery
  *
  * @name history
  * @cat Plugins/History
  * @author Klaus Hartl/klaus.hartl@stilbuero.de
  */
  $.fn.history = function(callback) {

    return this.click(function(e) {
      // add to history only if true click occured,
      // not a triggered click...
      if (e.clientX) {
        // ...and die if already active
        //alert("inside if");
        if (this.hash == location.hash) {
          //alert("return false");
          return false;
        }
        $.ajaxHistory.update(this.hash);
      }
      if (typeof callback == 'function') {
        //alert("call back");
        callback.call(this);
      }
      //alert("History");
    });
  };

})(jQuery);

//$(document).ready(function() {

//  $(".remoteInput").blur(function() {
//    var targetAnchor = $("#" + $(this).attr("targetAnchor"));
//    targetAnchor.attr({ "href": targetAnchor.attr("href") +"?"+ $(this).val() });
//    alert(targetAnchor.attr("href"));
//  });

//});

/*
var logger;
$(function() {
logger = $('<div style="position: fixed; top: 0; overflow: hidden; border: 1px solid; padding: 3px; width: 120px; height: 150px; background: #fff; color: red;"></div>').appendTo(document.body);
});
function log(m) {    
logger.prepend(m + '<br />');
};
*/

