
if(typeof(M)=='undefined') {M = {}}
M.GalleryController = $.sammy(function() {
    
  // using M.gallery because this.gallery gets reset for some reason.
  this.before( function () {    
    if (!M.gallery) {M.gallery = new M.Gallery({})}
    this.galleries = {
      'slideshow' : {gallery: 'slideshow', id: 10449520, key: 'H2ru8'},
      'portraits' : {gallery: 'portraits', id: 10438767, key: 'KzTZK'},
      'children'  : {gallery: 'children',  id: 10439644, key: 'K7jV3'},
      'family'    : {gallery: 'family',    id: 10446407, key: '5D7LU'},
      'nature'    : {gallery: 'nature',    id: 10446848, key: 'WnYFR'}
    }
  })


  this.get('^$', function() {
    
    M.gallery.load_album( {gallery: 'slideshow', id: 10449520, key: 'H2ru8', advance: 4000} )
    
  });
  
  this.get('#/:gallery', function() {
    M.gallery.load_album( this.galleries[this.params.gallery] )
    pageTracker._trackPageview("/" + this.params.gallery)
  })

  this.get('#/:gallery/:cursor', function() {
    var options = this.galleries[ this.params.gallery ]
    options.cursor = this.params.cursor
    M.gallery.load_album(options)
    pageTracker._trackPageview("/" + this.params.gallery + "/" + this.params.cursor)
  })

});


if(typeof(M)=='undefined') {M = {}}
(function(){
  M.Gallery = function(options) {  //constructor
    this.options = options;
    M.Gallery.instances[options.id] = this;
  }
  
  M.Gallery.instances = {}
  M.Gallery.endpoint = "http://api.smugmug.com/services/api/json/1.2.2/"
  
  M.Gallery.prototype = {
    
    load_album: function(options, callback){
      
      var self = this

      var album = {id: options.id, key: options.key}
      this.gallery = options.gallery
      this.cursor = parseInt(options.cursor,10) || 0
      this.options.advance = this.options.advance || 0
      
      this.update_nav()
      
      this.images = []
      
      // after login, get the pictures, index them and show the first
      this.login(
      function(){
      
        self.get_gallery({
          AlbumID   : album.id,
          AlbumKey  : album.key
        }, 
        function(data) {
          
          self.index_images(data, 
          function(images) {
            
            self.place_and_show_images({before: 1, after: 2}, 
            function() {
              
              if (options.advance > 0) {
                self.auto_advance({rate: options.advance})
              } else {
                clearTimeout(self.advancer)
                self.bind_keys()
                self.init_next()
                self.init_prev()
                if (!self.reminder) self.init_reminder()
              }
              
              self.nice_things()
              
              if (callback) callback()
            })
            
          })
          
        })
        
      })
      
    },
    
    
    bind_keys: function() {
      var self = this
      if (!this.keys_bound) {
        $(document).bind('keydown', 'right',      function(ev) {ev.preventDefault(); self.next_image()} );
        $(document).bind('keydown', 'left',       function(ev) {ev.preventDefault(); self.prev_image()} );
        $(document).bind('keydown', 'down',       function(ev) {ev.preventDefault(); self.next_image()} );
        $(document).bind('keydown', 'up',         function(ev) {ev.preventDefault(); self.prev_image()} );
        $(document).bind('keydown', 'space',      function(ev) {ev.preventDefault(); self.next_image()} );
        $(document).bind('keydown', 'delete',     function(ev) {ev.preventDefault(); self.prev_image()} );
      }
      this.keys_bound = true
    },
    
    
    init_next: function() {
      
      var self = this
      
      if(this.safe_cursor(+1) == this.cursor) {  $('#next').fadeOut() }
      
      $('#next_hover')
      .attr('href', "#/" + this.gallery + "/" + this.safe_cursor(+1))
      .hover(
        function() {
          if (self.safe_cursor(+1) != self.cursor) { $('#next').fadeIn() }
        },
        function() {
          $('#next').fadeOut()
        }
      )
      
    },
    
    
    init_prev: function() {
      
      var self = this
      
      if(this.safe_cursor(-1) == this.cursor) {  $('#prev').fadeOut() }
      
      $('#prev_hover')
      .attr('href', "#/" + this.gallery + "/" + this.safe_cursor(-1))
      .hover(
        function() {
          if (self.safe_cursor(-1) != self.cursor) { $('#prev').fadeIn() }
        },
        function() {
          $('#prev').fadeOut()
        }
      )
      
    },
    
    
    // Use the APIKey to login to Smugmug anonymously
    // and store the session key.
    login: function(callback) {
      
      if (this.session) {callback(); return}
      
      var self = this
      
      this.get({
        method: 'smugmug.login.anonymously',
        APIKey: 'PI3BTcC0zU8HYD2UodxRYoaHJUn9Q2LC'
      }, function(data) {
        self.session = data.Login.Session.id
        callback()
      })
      
    },
    
    
    index_images: function(data, callback) {
            
      var self = this
      var diptych = {diptych:true}
    
      $.each(data.Album.Images, function(){
        if (this.Width > this.Height) {
          
          self.images.push(this)
          
        } else {
          
          if (!diptych.left) {
            diptych.left = this
            diptych.id = this.id  //diptychs get the id of the left photo
          } else {
            diptych.right = this
          }
          if (diptych.right) {
            self.images.push(diptych)
            diptych = {diptych:true}
          }
          
        }
      })
    
      callback(self.images)
    
    },
    
    
    prev_image: function(callback) {
      document.location = "#/" + this.gallery + "/" + this.safe_cursor(-1)
      if (callback) callback()
    },
    
    
    next_image: function(callback) {
      document.location = "#/" + this.gallery + "/" + this.safe_cursor(+1)
      if (callback) callback()
    },
    
    
    safe_cursor: function(delta) {
      return Math.min( Math.max(this.cursor + delta, 0), this.images.length-1 )
    },
    
    
    // Safely set the cursor, show a photo if it has changed
    set_cursor: function(i, callback) {
      
      i = parseInt(i,10)
      var cursor = this.cursor
      this.cursor = Math.min( Math.max(i, 0), this.images.length-1 )
      
      if( this.cursor !== cursor) {
        this.place_and_show_images( {before: 1, after: 2}, callback )
      }
      
    },
    
    
    // Place images in the DOM and then show the one specified by cursor
    place_and_show_images: function(opt, callback) {
      
      var self = this
      
      $('.image:visible').hide()
      $('#loading').show()
      $('#loading .progress_bar').css({width: '0%'}).animate({width: '100%'}, 1500)
      
      this.place_images(opt,
      function(cursor_photo) {

          $('#loading').hide()
          self.show_image( cursor_photo, callback )
          
      })
      
    },
    
    
    // Place images in the DOM and run callback once all are loaded.
    place_images: function(opt, callback) {
      
      var self = this
      
      var first     = Math.max(0, this.cursor - opt.before)
      var last      = Math.min(this.images.length - 1, this.cursor + opt.after)
      var expected  = last - first + 1
      var loaded    = 0
      var i
      
      for (i = first; i <= last; i++) {
        
        this.place_image( this.images[i], 
        function(photo) {
          
          loaded ++
          
          if ( $(photo).attr('rel') === self.cursor_photo_id() ) {
            callback($(photo))
          }
            
        })
        
      }
      
    },
    
    
    cursor_photo_id: function() {
      return this.images[this.cursor].id.toString()
    },
    
    
    // Put an image from the images array in the DOM. "Images" can be either photos or diptychs
    place_image: function(image, callback) {
      
      if( image.diptych ) {
        this.place_diptych(image, callback)
      } else {
        this.place_photo(image, callback)
      }
      
    },
    
    
    // Put a photo from the images array in the DOM.
    place_photo: function(photo_in, callback) {
    
      var photo = $('.photo[rel=' +photo_in['id']+ ']')[0] 
      
      if (!photo) {
        
        $('<img style="display:none"/>')
          .attr('rel', photo_in['id'])
          .load(
          function() {
            callback( $(this)[0] )
          })
          .attr('src', photo_in.LargeURL)
          .addClass('photo image')
          .appendTo('#canvas')
          
          
      } else {
        callback(photo)
      }
      
    },
    
    
    // Take a diptych object from the images array and place it in the Dom
    place_diptych: function(diptych_in, callback) {
      
      var diptych = $('.diptych[rel=' +diptych_in.id + ']')[0]
      var loaded = 1
      var image_loaded = function(){  // run the callback once both diptych parts are loaded
        if (loaded++ === 2 ) {
          callback( $('.diptych[rel=' +diptych_in.id+ ']')[0] )
        }
      }
      
      if (!diptych) {
        new_diptych = $('<div class="diptych" style="display:none"/>')
        .addClass('diptych image')
        .attr('rel', diptych_in.id )
        .append( 
          $('<img />')
          .load(image_loaded)
          .attr('src', diptych_in.left.LargeURL)
          .addClass('left')
         )
        .append(
          $('<img />')
          .load(image_loaded)
          .attr('src', diptych_in.right.LargeURL)
          .addClass('right')
         )
        .appendTo('#canvas')

      } else {
        callback(diptych)
      }
      
    },
    
    
    // show_image_by_index: function(index, callback) {
    //   this.show_image( this.images[index], callback )
    // },
    
    
    // Once images are in the DOM by the place_* methods, we can reveal them.
    show_image: function(photo, callback) {
      
      var id = photo.length ? photo[0].id : photo.id  // handles diptychs
      
      var fadeIn = function() {
        photo.fadeIn('slow')
        if (callback) { callback() }
      }
      
      var visible = $('.image:visible')
      if (visible.length) { 
        $('.image:visible').fadeOut('fast', fadeIn) 
      } else {
        fadeIn()
      }
      
    }, 
    
    
    auto_advance: function(options){
      
      var self = this
      
      this.advancer = setTimeout(
      function(){
        self.set_cursor( (self.cursor + 1) % self.images.length )
        self.auto_advance(options)
      }, options.rate)
      
    },
    
    
    init_reminder: function() {
      this.reminder = setTimeout(
      function() {
        $('#next').fadeIn()
        $('#next').fadeOut()
        $('#next').fadeIn()
      }, 5000)
    },
    
    
    //--------------------------------------- Network
    // Returns gallery data from smugmug. Caches the results too.
    get_gallery: function(params, callback) {
      
      var self = this
      
      this.gallery_data = this.gallery_data || {}
      if (this.gallery_data[params.AlbumID]) { callback( this.gallery_data[params.AlbumID] ); return }
      
      params.Heavy = true
      params.method = 'smugmug.images.get'
      
      this.get(params, 
      function(data) {
        self.gallery_data[params.AlbumID] = data
        callback(data)
      })
      
    },
    
    
    // --------------------------------------- Nice Things
    nice_things: function() {
      
      var self = this
      
      if (this.total_nice_things) return
      
      this.total_nice_things = $('#nice_things li').length
      this.nice_things_cursor = 1
      
      setTimeout(function() {self.next_nice_thing()}, 1000)
    },
    
    
    next_nice_thing: function() {
      
      var self = this
      
      var fadeIn = function() {
        $('#nice_things li:nth-child('+(self.nice_things_cursor+1)+')').fadeIn('slow')
      }
      
      var visible = $('#nice_things li:visible')
      if (visible.length) {
        visible.fadeOut('slow', fadeIn)
      } else {
        fadeIn()
      }
      this.nice_things_cursor = (this.nice_things_cursor + 1) % this.total_nice_things
      setTimeout(function() {self.next_nice_thing()}, 30000)
      
    },
    
    
    update_nav: function() {
      
      $('#portfolios > li.on').removeClass('on')
      $('#portfolios .nav_' + this.gallery).addClass('on')
      
    },
    
    
    // Get anything from Smugmug via jsonp. Uses the
    // SessionID retrieved and stored by the this.login method.
    get: function(params, callback) {
      
      var url = M.Gallery.endpoint
      if (this.session) { params.SessionID = this.session }
      params.Callback = '?'
      var params_a = []
      
      $.each(params, function(k,v) {
        params_a.push( k + "=" + v)
      })
      
      // puts([ 'params_a' , params_a ])
      
      url += '?' + params_a.join('&')
      
      // puts([ 'url' , url ])
      
      $.getJSON(url,{},callback)
      
    }
  }
      
})();  // preserving the global namespace



// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
(function() {
    var cache = {};
    this.tmpl = function tmpl(str, data) {
      // Figure out if we're getting a template, or if we need to
      // load the template - and be sure to cache the result.
      var fn = !/\W/.test(str) ?
      cache[str] = cache[str] ||
      tmpl(document.getElementById(str).innerHTML) :

      // Generate a reusable function that will serve as a template
      // generator (and which will be cached).
      new Function("obj",
        "var p=[],print=function(){p.push.apply(p,arguments);};" +

        // Introduce the data as local variables using with(){}
        "with(obj){p.push('" +

        // Convert the template into pure JavaScript
        str.replace(/[\r\t\n]/g, " ")
         .replace(/'(?=[^%]*%>)/g,"\t")
         .split("'").join("\\'")
         .split("\t").join("'")
         .replace(/<%=(.+?)%>/g, "',$1,'")
         .split("<%").join("');")
         .split("%>").join("p.push('")
         + "');}return p.join('');");

        // Provide some basic currying to the user
				return data ? fn(data) : fn;
    };
})();

function puts(s) { if (typeof(console) !== 'undefined') console.log(s) }