(function(){
  
  var slides = [],
      laSlide;
  
  function Slide( elem, n ){
    var elem = this.elem = $( elem ),
        bg;
    
    this.n = n || 0;
    this.id = elem[0].id || 'slide-' + this.n;
    this.kind = (/(work|product)/.exec( elem[0].className ) || [] )[1];
    
    this.position = function( x ){
      elem.css({ left: x * 100 + '%' });
      bg.css({ left: x * 100 + 50 + '%' });
    };
        
    // Init
    var src = $('img.background', elem );
    bg = $('<section />').append( src ).appendTo('#bg');
  }
  
  function Work( elem ){
    var title = this.title = $('h2.caption', elem ).text();
  }
  
  function Nav(){
    
  }
  
  function syncDetailsSlide( width ){
    var details = $('#details').show(),
        d_width = details.width() || 75;

    return function( val ){
      var pos = val + width - d_width;
      details.stop(true).css({ left: pos > 0 ? 0 : pos });
    };
  }
  
  function showDetailsButton(){
    $('#details').stop( true ).show().animate({ left: 0 }, 210 );
  }
  
  function hideDetailsButton(){
    $('#details').stop( true ).show().animate({ left: -100 });
  }
  
  function showLabel( slide ){
    var label = $('#caption span');
    if( ! slide.work ) return;
    
    if( slide.work.title )
      label
        .text( slide.work.title )
        .css({ left: -label.width() - 20 })
        .delay(40)
        .animate(
          { left: 0 },
          // { duration: 320, easing:'easeInOutQuint', step: syncDetailsSlide( label.width() ) }
          320, 'easeInOutQuint'
        );
        
    setTimeout( showDetailsButton, 410 );
  }
  
  function hideLabel(){
    var label = $('#caption span');
    label
      .stop( true )
      .animate(
        { left: -label.width() - 20 },
        { duration: 210, step: syncDetailsSlide( label.width() ) }
        // 170
      );
    
    setTimeout( hideDetailsButton, 90 );
  }
  
  function show( slide ){
    var planes = $('#portal .plane, #bg'),
        dir = 1;
        
    if( slide.n === laSlide.n ) return;
    
    if( ( slide.n < laSlide.n || ( laSlide.n === 0 && slide.n === slides.length - 1 )) && 
       !( laSlide.n === slides.length - 1 && slide.n === 0 ))
      dir = -1;
    
    for( var n=0, l=slides.length; n < l; n++ )
      slides[ n ].position( 2 );
      
    laSlide.position( dir>0 ? 0 : 1 );
    slide.position( dir>0 ? 1 : 0 );
    
    planes.css({ left: dir>0 ? '0%' : '-100%' });
    
    $('#portal .plane').css({ overflow: 'hidden' });
    $('#portal article').addClass('hidden');
    
    planes.animate(
      { left: dir>0 ? '-100%' : '0%' },
      760,
      'easeOutExpo',
      function(){
        laSlide.position( 2 );
        laSlide = slide;
        laSlide.position( 0 );
        planes.css({ left: '0%' });
      
        laSlide.elem.removeClass('hidden');
        $('#portal .plane').css({ overflow: 'visible' });
      }
    );
    
    loadSlideAssets( $('.images', laSlide.elem ) );
    setTimeout(function(){ showLabel( slide ); }, 490 );
    
    $('aside.caption').show();
    hideLabel();
  }
  
  function next(){
    var n = laSlide.n + 1;
    showN( n >= slides.length ? 0 : n );
  }
  
  function prev(){
    var n = laSlide.n - 1;
    showN( n < 0 ? slides.length - 1 : n );
  }
  
  function showN( n ){
    var id = slides[n].id;
    window.location.hash = '/' + ( id === 'slide-0' ? '' : id );
  }

  
  function findSlide( name ){
    for( var n=0, l=slides.length; n < l; n++ )
      if( slides[ n ].id === name )
        return slides[ n ];
  }
  
  function video( src, cbk ){
    var can = detectVideoSupport(),
        uri = $( src ).attr('href'),
        wrap = $('<div class="video-wrap"/>').insertAfter( src );
        
        
    if( can.html5 ){
    // if( true ){
      var _uri = uri.replace(/\.(\w+)$/, can.webm ? '.webm' : can.mp4 ? '.$1' : '.ogv'),
          vid = $('<video width="870" preload="none" />').appendTo( wrap );
      
      vid.attr('src', _uri );
      
      var _poster = poster( vid, { uri: _uri, bigstart: bigstart }).appendTo( wrap ),
          _controls = controls( vid, { ended: ended}).hide().appendTo( wrap );
      
      function ended(){
        _poster.stop(true).fadeIn( 120 );
        _controls.stop(true).delay( 100 ).fadeOut( 120 ).removeClass('visible');
      }
      
      function bigstart(){
        _controls.stop(true).fadeIn( 120 ).addClass('visible');
      }
      cbk && cbk.call( vid );
    }
    else {
      var vid = {
        play: function(){
          $('<div />')
            .appendTo( wrap )
            .flash({
              src: '/swf/flayr.swf',
              width: 870, height: 490,
              flashvars: {
                movie: uri,
                preview: uri.replace(/\.(\w+)$/, '.poster.jpg'),
                controls: 'seek',
                color_controls: '#4d4d4d',
                color_background: '#ffffff',
                color_slider: '#999999',
                color_bar: '#000000',
                color_buffer: '#ebebeb',
                autoplay: 'true'
              }
            });
        },
        src: uri
      };
      
      wrap.css({ width: 870, height: 490 });
      poster( vid ).appendTo( wrap );
      // <script type="text/javascript">var so = new SWFObject("http://www.flayr.net/serve/swf/flayr.swf?movie=http://www.flayr.net/media/games.flv&preview=&name=&controls=seek&color_controls=#4d4d4d&color_background=#ffffff&color_slider=#999999&color_bar=#000000&color_buffer=#ebebeb", "flayr_player_id", "620", "375", "8");so.write("div_to_replace");</script>
      
      
      
      // var div = $('<div style="width:870px; height:490px;" />').insertAfter( src ),
      //     player = dumb_player.create( div, uri );
      cbk && cbk();
    }

    $( src ).remove();
  }
  
  function poster( video, opts ){
    video = $(video)[0];
    opts = $.extend({ uri: video.src, bigstart: function(){} }, opts );
    
    var img = $('<img class="poster" />'),
        btn = $('<button class="big-play">Play</button>');
    
    img.attr('src', opts.uri.replace(/\.(\w+)$/, '.poster.jpg') );
    
    btn.add( img ).click( function( e ){
      video.play();
      img.fadeOut( 270 );
      btn.fadeOut( 160 );
      opts.bigstart();
    });
    
    return img.add( btn );
  }
  
  function controls( video, opts ){
    video = $(video)[0];
    opts = $.extend({ ended:function(){} }, opts );
    
    var con = $('<div class="controls" />'),
        bar = $('<div class="bar" />').appendTo( con ),
        track = $('<div class="track" />').appendTo( bar ),
        progress = $('<div class="progress" />').appendTo( bar ),
        playpause = $('<button class="play-pause">Play/Pause</button>').appendTo( con );
        
    var paused = true,
        total = 0,
        loaded = 1,
        pos = 0,
        pos_ms = 0;
    
    function seek( t ){
      var min = video.seekable && video.seekable.start() || 0,
          max = video.seekable && video.seekable.end() || 0;
      
      if( t.pageX )
        t = ((t.pageX - bar.offset().left) / bar.width()) * total;
        
      if( t < min ) t = min;
      if( t > max ) t = max;
              
      video.currentTime = t;
    }
    
    function format( s ){
    	var min = Math.floor(s/60)<10 ? "0"+Math.floor(s/60) : Math.floor(s/60),
    	    sec = Math.floor(s-(min*60))<10 ? "0"+Math.floor(s-(min*60)) : Math.floor(s-(min*60));
    	return min + ":" + sec;
    }
    
    $( video ).bind({
      play: function(){
        paused = false;
        playpause.addClass('pause');
      },
      pause: function(){
        paused = true;
        playpause.removeClass('pause');
      },
      ended: function(){
        video.currentTime = 0;
        video.pause();
        opts.ended();
      },
      timeupdate: function(){
        pos = video.currentTime;
        pos_ms = pos * 1000;
      },
      progress: function( e ){
        if( e && e.total && e.loaded )
          loaded = Math.round( e.loaded / e.total );
        else if( video.buffered )
          loaded = video.buffered.end() / video.duration;
        track.css('width', Math.round(loaded * 100) + '%');
      }
    });
    
    playpause.add( video ).mousedown( function( e ){
      if( paused )
        video.play();
      else
        video.pause();
    });
    
    var dragging = false, wasplaying = false;
    bar.mousedown(function( e ){ dragging = true; video.pause(); wasplaying = !paused; seek( e ); });
    $( document )
      .mouseup(function( e ){ if( dragging && wasplaying ) video.play(); dragging = false; })
      .mousemove(function( e ){ if( dragging ) seek( e ); });
    
    
    $(video).closest('.video-wrap')
      .mouseenter(function(){ if( con.hasClass('visible') ) con.stop(true).fadeTo( 120, 1 ); })
      .mouseleave(function(){ if( con.hasClass('visible') ) con.stop(true).fadeTo( 120, 0 ); });
    

    (function setup(){
      if( video.readyState )
        total = video.duration;
      else
        setTimeout( arguments.callee, 50 );
    })();
    
    (function timeline(){
      var tick = 100;
      
      if( total && !paused )
        pos_ms += tick;
      
      var w = Math.floor( pos_ms / total / 1000 * bar.width() );
      progress.css('width', w );
      setTimeout( arguments.callee, tick );
    })();
    
    return con;
  }
  
  function image( src, cbk ){
    function loaded(){
      $( this ).fadeIn( 160, resize );
      cbk && cbk.call( this );
    }
    $('<img />')
      .addClass( src.className )
      .load( loaded )
      .insertAfter( src )
      .attr('src', $( src ).attr('href') );

    $( src ).remove();
  }
  
  function loadSlideAssets( set, cbk ){
    if( set.hasClass('assets-loaded') ) return;
    set.addClass('assets-loaded');
    
    var As = set.find('a'),
        loaded = 0,
        safety, isDone;
    
    As.each( function( x ){
      if( /video/.test( this.className ) )       
        video( this, tick );
      else
        image( this, tick );
    });
    
    safety = setTimeout( done, 1800 );
    
    function tick(){
      if( ++loaded < As.length ) return;
      clearTimeout( safety );
      done();
    }
    function done(){
      if( isDone ) return;
      $('<div class="clear" />').appendTo( set );
      isDone = true;
      cbk && cbk();
    }
  }
  
  function loadPortfolioImages( n ){
    n = typeof n === 'number' ? n : 0;
    var sets = $('#portal article .images:not(.assets-loaded)');
    if( sets.length < 1 ) return;

    loadSlideAssets(
      n%2 ? sets.first() : sets.last(),
      function(){ loadPortfolioImages( n + 1 ); }
    );
  }
  
  function initSlides(){
    $('#portal article').each( function( x, el ){
      var id = el.id,
          square = $('<a href="#"/>').appendTo('nav.slides'),
          slide;
      
      if( x === 0 ) square.addClass('default');
      
      slide = new Slide( el, x )
      slide.position( x );
      slides.push( slide );
      
      square.attr('href', '/' + id ).address();
      if( slide.kind )
        square.addClass( slide.kind );
      
      if(! $(this).hasClass('default') )
        slide.work = new Work( el );
      else
        laSlide = slide;
      
    });
    
    function closeDetails( e ){
      $('#portal').stop( true ).animate({ scrollTop: 0 });
    }
    $('#portal article .page').mousedown( function( e ){ e.stopPropagation(); });
    $('#portal .header .close, #portal').mousedown( showDetails );
    $(document).keydown(function( e ){ if( e.keyCode === 27 ) closeDetails( e ); });
    
    $(window).load( loadPortfolioImages );
  }
  
  
  var deetzShowing = false;
  
  function showDeetz( fast, hide ){
    var info = $('#more-info'),
        tagline = $('#tagline');
        
    $('#tagline').animate(
      { left: hide ? '0%' : '-100%' },
      { step: function( val ){
          info.css({ left: val + 100 + '%' });
        },
        duration: fast ? 0 : 500
      }
    );
    deetzShowing = !hide;
  }
  
  function hideDeetz( fast ){
    showDeetz( !!fast, true );
  }
  
  function clientList(){
    var info = $('#more-info .right .info'),
        expr = $('#more-info .right .experience'),
        easing = 'easeOutExpo',
        duration = 290;
        
    $('#show-client-list').click(function(){
      info.stop(true).animate({ left: '-100%' }, duration, easing );
      expr.stop(true).animate({ left: '0%' }, duration, easing);
    });
    
    $('#hide-client-list, .experience').click(function(){
      info.stop(true).animate({ left: '0%' }, duration, easing);
      expr.stop(true).animate({ left: '100%' }, duration, easing);
    });
  }
  
  function initHome(){
    var div = $('#tagline'),
        pape = Raphael( div[0], 1045, 240 );
    
    $('h1', div ).hide();
    pape.path( paths.tagline ).attr({ stroke: false, fill:'#fff' });
    $('#more-info .close').address();
    clientList();
    $('article.default .details, #more-info').click(function( e ){ e.stopPropagation(); });
    $('article.default').click( function(){
      if( $.address.pathNames()[0] === 'about' )
        $.address.value('/');
      else
        next();
    });
  }
  
  function showDetails( e ){
    var wh = $( window ).height(),
        pos = $('#portal').scrollTop(),
        prop = pos < wh / 2 ? { scrollTop: $( window ).height() - 70 } : { scrollTop: 0 };
        
    $('#portal').stop( true ).animate( prop, 300, 'easeOutExpo');
  }
  
  function theaterLights(){
    var chrome = $('.chrome'),
        top_chrome = $('.chrome.top'),
        bg = $('#bg'),
        portal = $('#portal');
    
    var _opacity = 1,
        wh;
        
    $(window).resize(function(){ wh = $(window).height(); }).resize();
    
    portal.scroll(function(){
      
      var pos = portal.scrollTop(),
          opacity = pos / (wh * 0.8);
      
      opacity = 1 - ( opacity > 1 ? 1 : opacity ) * 0.8;
      opacity = Math.round( opacity * 100 ) / 100;
      
      if( opacity === _opacity ) return;
        
      chrome.css({ opacity: opacity });
      top_chrome.css({ zIndex: opacity>0.25 ? 100 : 5 });
      bg.css({ opacity: opacity / 2 + 0.5 });
      _opacity = opacity;
    });
    
    $('#details').click( showDetails );
  }
  
  
  function resize(){
    var section = $('#bg section'),
        img = $('#bg section img'),
        ww = $(window).width(),
        sh = section.height(),
        ih = img.height() || sh;
  
    section.css({ marginLeft: -ww/2, marginTop: -sh/2 });
    img.css({ marginTop: -ih/2 });
    $('article .page').css({ marginTop: sh + 15 + 'px' });
  }
  
  function globalEvents(){
    arrows();
    keyboard();
  }

  function arrows(){
    var _prev = $('<button id="prev" />'),
        _next = $('<button id="next" />');
    
    _prev.click( prev );
    _next.click( next );
    
    var both = _prev.add( _next )
      .css({ opacity: 0 })
      .addClass('big-arrow chrome')
      .appendTo('body');
      
    function enter(){
      both.stop(true).fadeTo( 600, 0.25 );
    }
    
    function exit(){
      both.stop(true).fadeTo( 140, 0 );
    }
    
    $( document ).mousemove( function( e ){
      if( e.pageY > 80 && e.pageX < 80 || e.pageX > $(window).width() - 80 )
        enter();
      else
        exit();
    });
    
    $('nav.slides').mousemove( function( e ){
      e.stopPropagation();
      exit();
    });
  }
  
  function keyboard(){
    $( document ).keydown( function( e ){
      if( e.keyCode === 37 )
        !e.preventDefault() && prev();
      if( e.keyCode === 39 )
        !e.preventDefault() && next();
      if( e.keyCode === 40 && $('#portal').scrollTop() <= 60 ){
        e.preventDefault();
        showDetails();
      }
    });
  }
  
  function iOS(){
    window.canTouch = isTouchDevice();
    if( ! canTouch ) return;
    
    swipe();
    touchScroll();
  }
  
  function swipe(){
    var start, last,
        clock = 0;
    
    document.addEventListener('touchstart', function(e){
      start = { x: e.touches[0].screenX, y: e.touches[0].screenY };
      clock = +(new Date);
    });
    
    document.addEventListener('touchmove', function(e){
      last = { x: e.touches[0].screenX, y: e.touches[0].screenY };
    });
    
    document.addEventListener('touchend', function(e){
      if( !last ) return;
      
      var dx = last.x - start.x,
          dy = last.y - start.y,
          dt = +(new Date) - clock;
          
      if( Math.abs( dx ) / 2 > Math.abs( dy ) &&
          Math.abs( dx / dt ) > 0.45 ){
        if( dx < 0 ) next();
        else prev();
      }
    });
  }
  
  function touchScroll(){
    var portal = $('#portal'),
        scroll = 0,
        start;
    
    portal[0].addEventListener('touchstart', function(e){
      start = { x: e.touches[0].screenX, y: e.touches[0].screenY };
      scroll = portal.scrollTop();
    });
    
    portal[0].addEventListener('touchmove', function(e){
      if( e.touches.length > 1 ) return;
      e.preventDefault();
      portal.scrollTop( scroll + (start.y - e.touches[0].screenY) * 3 );
    });
  }
  
  function isTouchDevice(){
    var el = document.createElement('div');
    el.setAttribute('ongesturestart', 'return;');
     
    return (typeof el.ongesturestart === "function" );
  }
  
  function detectVideoSupport(){
    if( !(this instanceof arguments.callee) ) return new arguments.callee();
    
    var el = document.createElement('video') || false,
        mp4 = el && el.canPlayType && el.canPlayType("video/mp4"),
        ogg = el && el.canPlayType && el.canPlayType("video/ogg"),
        webm = el && el.canPlayType && el.canPlayType("video/webm");
        
    this.html5 = el && typeof el.canPlayType !== "undefined";
    this.mp4 = this.html5 && mp4 === "maybe" || mp4 === "probably";
    this.ogg = this.html5 && ogg === "maybe" || ogg === "probably";
    this.webm = this.html5 && webm === "maybe" || webm === "probably";
    
    return this;
  }

  
  function dispatch( e ){
    var name = $.address.pathNames()[0],
        page = findSlide( name );
        
    $('nav.slides a').removeClass('selected');
    $('nav.slides a[href="' + e.value + '"]').addClass('selected');
    
    $('nav.slides a').removeClass('right-kind');
    
    $('video').each(function(){ this.pause(); });
    
    if( page ){
      show( page );
    }
    else if( page = /(work|product)/.exec( name ) ){
      page = page[1];
      
      if( laSlide.kind !== page ){
        for( var n=0, l=slides.length; n < l; n++ ){
          if( slides[n].kind === page ){
            show( slides[n] );
            break;
          }
        }
      }
      
      $('nav.slides a.' + page ).addClass('right-kind');
    }
    else if( name === 'about' ){
      show( slides[0] );
      showDeetz( laSlide.n !== 0 );
      $('nav.slides a.default').addClass('selected');
    }
    else {
      show( slides[0] );
      if( deetzShowing )
        hideDeetz( laSlide.n !== 0 );
    }
  }
  

  $( function(){
    initSlides();
    initHome();
    theaterLights();
    
    $( window ).resize( resize );
    $('#bg img').load( resize );
    
    $('#logo').click( function( e ){ $.address.value('/'); });
    $.address.change( dispatch );
    
    iOS();
    globalEvents();
  });
  
})();
