
// does the browser have history API support
var HISTORY_SUPPORT = (typeof history.pushState === 'function');

// executed after the DOM is ready
$(document).ready(function () {
  addMenuClickControls();

  if (HISTORY_SUPPORT) {
    // browser has history API support
    API.add(window.location, $("#asyncContent").html());

    delegateLinksAsync();
    setLayoutFromLocation(window.location, true);

    // listen for hash changes
    window.onpopstate = function(evt) {
      API.getAsyncContent(window.location);
    };
  } else {
    // browser does not support history API
    delegateLinks();
    setLayoutFromLocation(window.location);

    // listen for hash changes
    $(window).bind('hashchange', function() {
      setLayoutFromLocation(window.location);
    });
  }
});


// external link test
var isExternalLink = (function () {
  var internalRegExp = new RegExp('/' + window.location.host + '/');
  var imageRegExp = new RegExp('/_images/');

  return function (href) {
    return (!internalRegExp.test(href) || imageRegExp.test(href))
  };
}());


// toggle the Fork Me ribbon, only show when
// the introduction page is displayed
function showForkMeRibbon (pathname) {
  if (pathname === '/getting_started/introduction.html') {
    $('#forkMe').show();
  } else {
    $('#forkMe').hide();
  }
};


// delegate click events
function delegateLinks () {
  $('body').delegate("a", "click", function(evt) {
    if(isExternalLink(this.href)) {
      // open in a new window
      evt.preventDefault();
      evt.stopPropagation();
      window.open(this.href, "_blank");
    }
  });
};


// delegate click events
function delegateLinksAsync () {
  $('body').delegate("a", "click", function(evt) {
    if(isExternalLink(this.href)) {
      // open in a new window
      evt.preventDefault();
      evt.stopPropagation();
      window.open(this.href, "_blank");
    } else {
      evt.preventDefault();
      evt.stopPropagation();
      history.pushState(null, "", this.href);
      API.getAsyncContent(this);
    }
  });
};


// add menu tree click open/close actions
function addMenuClickControls () {  
  $('span.clickable').click(function(evt) {
    $(this).text($(this).text() === "+" ? "-" : "+").parent().next().toggle();
    return false;
  });
};


// expand the menus and adjust
// the +- indicator
function expandMenu (index, ul) {
  $(ul).show();
  $(ul).prev().find('span.clickable').text('-');
};


// set layout
var setLayoutFromLocation = (function () {
  var _ss, _loc = {};

  return function (loc, scroll) {
    // do nothing if the location has not changed
    if (loc.href === _loc.href) {
      return;
    }

    // toggle Fork Me ribbon on and off
    showForkMeRibbon(window.location.pathname);

    var i, id;
    var urlId = GLOBALS.map[loc.pathname + loc.hash];
    var ss = GLOBALS.showSelect[urlId];

    if (_ss) {
      // hide any conditional menus
      for (i in _ss[0]) {
        if (_.indexOf(ss[0], _ss[0][i]) === -1) {
          $('#id' + _ss[0][i]).hide();
        }
      }
      // unselect any highlight menu items
      for (i in _ss[1]) {
        if (_.indexOf(ss[1], _ss[1][i]) === -1) {
          $('#id' + _ss[1][i]).removeClass('selected');
        }
      }
    }

    // expand any hidden div's containing conditional
    // menus
    for (i in ss[0]) {
      $('#id' + ss[0][i]).show();
    }

    // expand any nested menus and highlight the 
    // necessary menu items
    for (i in ss[1]) {
      id = '#id' + ss[1][i];
      $(id).addClass('selected');
      $(id).closest('li').find('ul').each(expandMenu);
      $(id).parents('ul').each(expandMenu);
    }

    // add sub menu name to the title
    $('#hash').text(ss[2] ? ' : ' + ss[2] : '');

    // format the code blocks
    if (!_loc || _loc.pathname !== loc.pathname) {
      prettyPrint();
    }

    // remember the current location
    _ss = ss;
    _loc.pathname = loc.pathname;
    _loc.href = loc.href;

    // set browser title
    document.title = $('#display_title').text();

    if (scroll) {
      if (loc.hash) {
        var locHash = loc.hash.replace('.', '\\.');
        $(window).scrollTop($(locHash).offset().top);
      } else {
        $(window).scrollTop(0);
      }
    }
  };
}());


// make ajax call to get content
// asynchronously
var API = (function () {
  var _ctx = {};
  _ctx.uid = 0;
  _ctx._loc = {};
  _ctx.cache = {};

  // generate callback function with
  // unique callback
  var _cb = function () {
    var _uid = ++_ctx.uid;
    return function (data) {
      // check the request unique id
      if (_ctx.uid === _uid) {
        // cache page
        _ctx.cache[_ctx.loc.pathname] = data;
        // update page
        _updatePage(data);
      }
    }
  };

  var _updatePage = function (data) {
    // update context
    if (data) {
      $("#asyncContent").html(data);
    }
    // set layout
    setLayoutFromLocation(_ctx.loc, true);
    // remember the current page
    _rememberPage(_ctx.loc);
  };

  var _rememberPage = function (loc) {
    _ctx._loc.href = loc.href;
    _ctx._loc.pathname = loc.pathname;
    _ctx._loc.hash = loc.hash;  
  };

  return {
    add: function (loc, data) {
      _ctx.cache[loc.pathname] = data;
      _rememberPage(loc);
    },
    getAsyncContent: function (loc) {
      // do nothing if the location has not changed
      if (loc.href === _ctx._loc.href) {
        return;
      }
      // add the new page location to context
      _ctx.loc = loc;
      
      if (loc.pathname === _ctx._loc.pathname) {
        // must be a hash change
        _ctx.uid++;
        _updatePage();
      } else {
        // look in the cache
        if (loc.pathname in _ctx.cache) {
          _ctx.uid++;
          _updatePage(_ctx.cache[loc.pathname]);
        } else {
          $.ajax({
            url: "/_async" + loc.pathname + loc.hash,
            success: _cb()
          });
        }
      }
    }
  };
}());




