(function(){
  //////////////////
  // HASH STUFF
  // Closure variables
  var cache = {};
  
  var curHash; // Current hash
  // Get current hash (+ update our variable)
  var getHash = function(){
    curHash = location.hash.substring(1);
    if (curHash == "index.html") curHash = "";
    // This is as good a place as any to ensure mouseOver gets reset
    if (curHash) mouseOver = false;
    return curHash;
  };
  getHash(); // Initialize



  //////////////////
  // JQUERY PLUGINS
  // OuterHtml
  jQuery.fn.outerHtml = function(s) {
    return (s) ? this.before(s).remove() : jQuery("<p/>").append(this.eq(0).clone()).html();
  };



  $(document).ready(function(){

    //////////////////
    // ANIMATION
    var lastMultiplier;
    myAnimator = (function(){ // fill out forward-declared function
      // Memoize offsets
      // Note: significant changes to functionality of this page would probably break our stuff
      // Currently, this function is mostly useless, except that we need to save the initial state (i.e., passing 0 for offset)
      var offset = function(elm, style, offset) {
        if (!elm.filter) elm = elms[elm]; // Expand element, if not already a jQuery

        // Parse out style's current value
        val = elm.css(style).match("(.*)px");
        if (!val) val = 0; else val = Number(val[1]); // We either got no match (value is 0) or a match (grab the match)

        // Initialize memo
        if (!((style+"Memo") in elm.data())) elm.data(style+"Memo", {});
        // Get memos
        var memo = elm.data(style+"Memo");
        // Set this offset if not already
        if (!( offset in memo )) {
          // If 0, store initial value; otherwise compute memo
          if (offset == 0) memo[offset] = val; else memo[offset] = memo[0] + offset;
          elm.data(style+"Memo", memo); // Save updated memo
        }
        return memo[offset];
      }

      // Elements to animate (the brass panels)
      var elms = {
        left: $( "#brassLeft" ), "top": $( "#brassTop" ),
        bottom: $( "#brassBottom" ), right: $( "#brassRight" )
      };

      // Store initial values for each one
      $.each(elms, function(name, elm) {
        offset(elm, "left", 0);
        offset(elm, "top", 0);
      });

      // Look at current state to retrieve the multiplier
      var getMultiplier = function() {
        // Must be entirely out if there's a hash
        if (curHash) return 5.5;
        // When mousing over, allow peek
        else return mouseOver ? 0.55 : 0;
      };

      function myAnimator(method) {
        var multiplier = getMultiplier();
        lastMultiplier = multiplier; // Save the current multiplier
        // Show panels if they are on screen
        if (multiplier < 4) $.each(elms, function(){
          this.show();
        });

        if (!method) method = "animate"; // How to get the panels where they should be

        // Function to call when we're finished
        var finished = function(){
          // Reassign states if our multiplier has pulled the panels from view
          $("#main > .start").toggleClass("state-open", lastMultiplier > 4);
        };

        // s1 and s2 are slopes, which we found somewhat by trial and error
        var s1 = 68, s2 = 190, speed = "fast";

        // We could compute the s1/s2 and positive/negative dynamically...but that would save us little effort.
        if (method == "animate") {
          elms.left[method]({left: offset("left", "left", -s1 * multiplier), "top": offset("left", "top", s2 * multiplier)}, speed, finished);
          elms["top"][method]({left: offset("top", "left", -s2 * multiplier), "top": offset("top", "top", -s1 * multiplier)}, speed, finished);
          elms.right[method]({left: offset("right", "left", s1 * multiplier), "top": offset("right", "top", -s2 * multiplier)}, speed, finished);
          elms.bottom[method]({left: offset("bottom", "left", s2 * multiplier), "top": offset("bottom", "top", s1 * multiplier)}, speed, finished);
        } else if (method == "css") {
          elms.left[method]({left: offset("left", "left", -s1 * multiplier), "top": offset("left", "top", s2 * multiplier)});
          elms["top"][method]({left: offset("top", "left", -s2 * multiplier), "top": offset("top", "top", -s1 * multiplier)});
          elms.right[method]({left: offset("right", "left", s1 * multiplier), "top": offset("right", "top", -s2 * multiplier)});
          elms.bottom[method]({left: offset("bottom", "left", s2 * multiplier), "top": offset("bottom", "top", s1 * multiplier)});
          // Synchronous
          finished();
        }

        return true;
      }
      return myAnimator;
    })();

    // Loading a new URL
    var load = function(url) {
      // Bring panels back together when you return to home
      if (!url) {
        mouseOver = false;
        myAnimator(); // Assume curHash is empty, hence multiplier of 0
        return;
      }

      // Clear current state
      $( '.stuffing' ).html(""); // Remove existing div's content

      // Use cache if possible, otherwise load AJAX
      if ( url in cache) $(".stuffing").html(cache[url]);
      else $.get(url, function(response){
          // Enter new contents
          cache[ url ] = $( response ).find("#mainContent").html();
          $(".stuffing").html(cache[ url ]);
          myAnimator();
      });
    };

    // Reload hash
    $(window).bind("hashchange", function(){
      load(getHash());
      myAnimator();
    }).trigger('hashchange');

    // If we start out with a hash, open the panels
    if (curHash) myAnimator("css");

    var mouseOver = false; // Set to initial state from outer closure

    // Supersede nav links
    // First, convert hrefs to hash tags
    $("#nav-parent a").attr("href", function(i, href){ return "#" + href; });

    // Now, animation and autoload functionality
    var navlinks = $("#nav").
      // The animation doesn't change between links, but the ajax loader does
      mousemove(function(){
        if (mouseOver || curHash) return;
        mouseOver = true;
        // Delay to prevent things being too frantic
        setTimeout(function(){
          if ( mouseOver )myAnimator();
        }, 300);
      }).mouseleave(function(){
        if (!mouseOver || curHash) return;
        mouseOver = false;
        myAnimator();
      }).find("a").
        each(function() {
            $(this).mousemove(function(){
              if (!curHash) load(this.href.substring(this.href.indexOf("#") + 1));
            })
          }).
        end().
      end().
      prev(".home").click(function(){
        // Shut panels
        myAnimator(0);
      });
  });
})();

