;(function($, window, document, undefined) {

var md = {
  
  init: function(pageId, sectionId, title) {
    
    var scene = this.scenes.get(pageId);
    scene.setData({
      id: pageId,
      sectionId: sectionId,
      title: title,
      content: $('#main').html()
    });
    this.scenes.swap(scene);
    
    // init ui
    this.ui.projectlist.init();
    this.ui.globalthinker.init();
    
    // run router
    this.app.run();
  },
  
  getLinks: function() {
    return '#logo, #mainnav a, #worklist a, .more a, .more';
  }
};

md.scenes = $.Scenery;

md.scenes.create('project-list', {
  setData: function(data) {
    data.content = '';
    this.__super__.setData.call(this, data);
  },
  
  init: function() {
    $('#main').html('');
  }
});

md.scenes.create('project-detail', {
  
  init: function() {
    var self = this,
        speed = 600,
        zmax = $('.images').find('figure').length + 5000,
        z = zmax;
    
    $('.images')
      .pager({
        items: 'figure',
        cycle: true
      })
      .pagernav({
        node: 'nav'
      })
      .find('figure')
        .zIndex(z)
      .end()
      .bind('pagerchange', function(e, ui) {
        z = ui.previousPageItems
          .stop(true)
          .animate({ width: 0 }, speed, 'easeInOutCubic', function() {
            $(this).css({ width: 620 }).hide();
            ui.pageItems.show(); // sic
          })
          .zIndex();
        if (z < 1) {
          z = zmax;
          ui.previousPageItems.zIndex(z);
        }
        ui.pageItems
          .zIndex(z - 1)
          .show();
      })
      .pager('page', 0);
  },
  
  exit: function(yield) {
    if ($.browser.msie)
      $('.images').fadeOut();
    if (yield)
      yield();
  }
});

md.ui = {};

md.ui.projectlist = {
  
  init: function() {
    $.getJSON('/works/', function(data) {
      $('#worklist')
        .html(data.content)
        .find('.row')
          .pager({
            items: '.projects li',
            perPage: 3,
            paginateBy: 3,
            cycle: true
          })
          .pagernav({
            node: 'nav ul'
          })
          .bind('pagerchange', function(e, ui) {
            $(this).find('.projects').animate({
              'marginLeft': ui.cycled ? (-320 * 3 * ui.page) : ('-=' + ui.direction * (320 * ui.pageItems.length))
            }, 600, 'easeInOutCubic');
          });
    });
  },
  
  select: function(slug) {
  },
  
  show: function() {
  },
  
  hide: function() {
  }
};

md.ui.globalthinker = {
  
  $element: null,
  
  tid: null,
  opacity: 1,
  delay: 1000,
  speedIn: 0,
  speedOut: 0,
  
  init: function() {
    this.$element = $('#globalthinker').show();
    this.opacity = this.$element.css('opacity');
  },
  
  show: function(block) {
    var self = this;
    this.hide();
    this.tid = setTimeout(function() {
      self.$element.stop(true).show().fadeTo(self.speedIn, self.opacity);
    }, this.delay);
  },
  
  hide: function() {
    clearTimeout(this.tid);
    this.$element.stop(true).fadeTo(this.speedOut, 0, function() {
      $(this).hide();
    });
  }
};

md.app = $.sammy('#main', function() {
  
  var isFirstRun = true;
  
  this.use('JSON');
  this.use('GoogleAnalytics');
  
  // routes
  
  this.get(/\/works\/([\w\-\_]+)\.html$/, function(context) {
    var slug = context.params['splat'][0];
    context
      .selectProject(slug)
      .load(context.patchURL('/works/' + slug + '.html'))
      .then(function(scene) {
        context.swap(scene);
      });
  });
  
  this.get(/\/works\/$/, function(context) {
    context
      .selectProject(null)
      .load(context.patchURL('/works/'))
      .then(function(scene) {
        context.swap(scene);
      });
  });
  
  this.get(/\/contact\/$/, function(context) {
    context
      .selectProject(null)
      .load(context.patchURL('/contact/'))
      .then(function(scene) {
        context.swap(scene);
      });
  });
  
  this.post(/\/contact\/$/, function(context) {
    var $form = $(context.target);
    context
      .selectProject(null)
      .send($.post, $form.attr('action'), context.params)
      .then(function(html) {
        $form.html(html);
      });
    return false;
  });
  
  this.get(/\/about\/$/, function(context) {
    context
      .selectProject(null)
      .load(context.patchURL('/about/'))
      .then(function(scene) {
        context.swap(scene);
      });
  });
  
  this.get(/\/$/, function(context) {
    context
      .selectProject(null)
      .load(context.patchURL('/'))
      .then(function(scene) {
        context.swap(scene);
      });
  });
  
  // swap
  
  this.swap = function(data, callback) {
    var context = this,
        initialHeight = this.$element().height(),
        finalHeight;
    
    var scenery = md.scenes,
        scene = scenery.get(data.id),
        currentScene = scenery.getCurrent();
    
    scene.setData(data);
    
    context.trigger('scene-loaded', {scene: scene});
    
    currentScene.exit(function() {
      
      context.$element()
        .css({height: initialHeight})
        .stop(true)
        .fadeTo(400, 0.0, 'easeInOutCubic', function() {
          
          finalHeight = $(this)
            .html(scene.getData().content)
            .css({height: 'auto'})
            .height();
          
          context.trigger('scene-before-show', {scene: scene});
          scene.init();
          
          //$(this).imagesLoaded(function() {
            $(this)
              .css({height: initialHeight})
              .stop(true)
              .animate({
                height: finalHeight
              }, 800, 'easeInOutCubic', function() {
                $(this).fadeTo(400, 1.0, 'easeInOutCubic', function() {
                  $(this).css({height: 'auto'});
                
                  if (callback) callback.apply();
                
                  scenery.swap(scene);
                  scene.enter();
                
                  // be a good sammy citizen
                  context.trigger('change');
                });
              });
          //});
        });
    });
  };
  
  // middleware
  
  this.before({only: {verb: 'get'}}, function() {
    if (isFirstRun) {
      isFirstRun = false;
      
      var scene = md.scenes.getCurrent();
      scene.init();
      scene.enter();
      
      // cancel route if the url does not contain the hashbang
      if (!(/#!/.test(document.location.toString()))) {
        this.stopThinking();
        return false;
      }
    }
    return this.thinking();
  });
  
  // events
  
  this.bind('run', function(e, data) {
    var context = this;
    if (!context.app._location_proxy.has_history) {
      $(document).on('click.md', md.getLinks(), function(e) {
        var href = $(this).attr('href');
        if (href && !e.isDefaultPrevented()) {
          e.preventDefault();
          context.redirect(context.normalizeURL(href));
        }
      });
    }
  });
  
  this.bind('check-form-submission', function(e, data) {
    var $form = $(data.form),
        url = $form.attr('action');
    // sammy chokes when submitting a form whose action attribute
    // is empty (so that it gets posted to the current page),
    // so we force the form's action attribute to the current location.
    url = (!url || url === '') ? this.app.getLocation() : url;
    // normalizeURL strips the leading slash but the form's action
    // must be an absolute path -- as always is the document's location.
    $form.attr('action', '/' + this.normalizeURL(url));
  });
  
  this.bind('scene-loaded', function(e, data) {
    this.stopThinking();
  });
  
  this.bind('scene-before-show', function(e, data) {
    var sceneData = data.scene.getData();
    document.title = sceneData.title;
    $('body')
      .removeClass(md.scenes.getCurrent().getData().sectionId)
      .addClass(sceneData.sectionId)
      .attr('id', sceneData.id);
    this.scrollTo(0);
  });
  
  // helpers
  
  this.helpers({
    
    scrollTo: function(node, options) {
      var opts = $.extend({}, {
        duration: 600,
        easing: 'easeInOutCubic'
      }, opts);
      $(window).scrollTo(node, opts);
    },
    
    thinking: function(block) {
      md.ui.globalthinker.show(block);
      return this;
    },
    
    stopThinking: function() {
      md.ui.globalthinker.hide();
      return this;
    },
    
    selectProject: function(slug) {
      md.ui.projectlist.select(slug);
      return this;
    },
    
    normalizeURL: function(url) {
      var loc = document.location.toString(),
          base = loc.split(/#!/)[0] || '';
      
      // ie worries that we'll leave the site and converts any links
      // of content that was loaded via ajax to absolute urls.
      // we strip the document's location if this is the case.
      if (url.substring(0, base.length) === base)
        url = url.substring(base.length);
      
      // strip the hashbang
      if (url.substring(0, 3) === '/#!')
        url = url.substring(3);
      
      // strip the leading slash
      if (url.substring(0, 1) === '/')
        url = url.substring(1);
      
      return url;
    },
    
    patchURL: function(url) {
      if ($.browser.msie)
        // ie caches pages based only on the url and will not reload
        // the page when requested via ajax. append a random value to the
        // query string to force ie into thinking it doesn't know about
        // this url.
        return url + '?' + (Math.floor(Math.random() * 900000) + 100).toString();
      return url;
    }
  });
});

$.md = window.md = md;

})(jQuery, this, this.document);
