/*

Class: Controllers

This is a namespace for all the classes that control interactive behavior on the
page. It also manages event messaging so that controllers can communicate with
each other.

*/
var Controllers = new Class({

  Implements: Events,
  
  initialize: function(cssPrefix) {
    this.cssPrefix = cssPrefix;
    this.controllers = [];
    this.countdown = 2;
    window.addEvent('domready', this.onReady.bind(this));
    this.addEvent('onReady', this.onReady.bind(this));
  },
  
  onReady: function() {
    
    // In order to initialize controllers safely, wait to make sure that both
    // the DOM is ready and that the 'onReady' custom event has been fired.
    // Firing 'onReady' indicates that all controllers have been added.
    this.countdown--;
    if (this.countdown === 0) {
      this.fireEvent('onBeforeInitialize');
      this.initializeControllers();
    }
  },
  
  initializeControllers: function(target) {
    
    var matches, selector;
    
    // After the page loads, search for elements with particular CSS classes
    // that correspond to JavaScript behavior controllers. Or if target is
    // included as an argument, initialize controllers within its contents.
    
    // Some special cases
    $$('img[longdesc]').addClass('JS_ImageCaption');
    $$('a.ss-send-to-phone').addClass('JS_SendToPhone');
    
    for (var property in this) {
      if ($type(this[property]) == 'class') {
        selector = '.' + this.cssPrefix + property;
        if ($type(target) == 'element') {
          matches = target.getElements(selector);
        } else {
          matches = $$(selector);
        }
        matches.each(function(el) {
          try {
            var controller = this[property];
            this.controllers.push(new controller(el, this));
          } catch(e) {
            this.handleException(e);
          }
        }.bind(this));
      }
    }
    
    if ($type(target) == 'element') {
      this.fireEvent('onWidgetInitialize', target);
    } else {
      
      // Notify any listeners that all controllers are done initializing. Also,
      // set a top-level CSS class to allow for progressive enhancement.
      
      this.fireEvent('onInitialize');
      $(document.body).addClass(this.cssPrefix + 'enabled');
    }
    
  },
  
  handleException: function(e) {
    dbug.log("Error: " + e.message +
             " [" + this.getExceptionOrigin(e) + "] ");
  },
  
  getExceptionOrigin: function(e) {
    if (e.fileName) {
      var file = e.fileName.match(/\/([^\/?]+)[^\/]*$/)[1];
      return file + ':' + e.lineNumber;
    } else {
      return "unknown origin";
    }
  }
  
});

var MoMA = new Controllers('JS_');

MoMA.Calendar = new Class({
  
  initialize: function(el, page) {
    this.el = el;
    this.page = page;
    this.el.getElements('.tabs a').each(function(tab) {
      tab.addEvent('click', this.tabClick.bind(this));
    }.bind(this));
  },
  
  tabClick: function(e) {
    e = new Event(e);
    e.preventDefault();
    
    this.el.getElement('.events .selected').removeClass('selected');
    this.el.getElement('.tabs .selected').removeClass('selected');
    
    var target = $(e.target).getAttribute('href').match(/#(.+)/)[1];
    $('tab-' + target).addClass('selected');
    $(e.target).addClass('selected');
    
    var date = this.el.getElement('.date');
    if (date) {
      date.set('html', $(e.target).get('rel'));
    }
  }
  
});

MoMA.Promotions = new Class({
  
  initialize: function(el) {
    
    var items = el.getElements('.item');
    
    if (items.length < 5) {
      el.getElement('.next').addClass('disabled');
    }
    
    if (items.length === 0) {
      return;
    }
    
    this.el = el;
    this.offset = 0;
    this.pageSize = items[0].getSize().x +
                    parseInt(items[0].getStyle('margin-right'), 10) +
                    parseInt(items[0].getStyle('margin-left'), 10);
    
    var contentWidth = el.getElement('.content').getSize().x;
    this.max = items.length * this.pageSize - contentWidth - 10;
    
    
    
    el.getElement('.prev').addEvent('click', this.prev.bind(this));
    el.getElement('.next').addEvent('click', this.next.bind(this));
    el.getElement('.slider').set('tween', {
      duration: 750,
      transition: Fx.Transitions.Quart.easeOut
    });
  },
  
  next: function() {
    if (this.el.getElement('.next').hasClass('disabled')) {
      return false;
    }
    this.offset -= this.pageSize;
    this.el.getElement('.slider').tween('left', this.offset);
    if (this.offset < -this.max) {
      this.el.getElement('.next').addClass('disabled');
    }
    this.el.getElement('.prev').removeClass('disabled');
    return false;
  },
  
  prev: function() {
    if (this.el.getElement('.prev').hasClass('disabled')) {
      return false;
    }
    this.offset += this.pageSize;
    this.el.getElement('.slider').tween('left', this.offset);
    if (this.offset === 0) {
      this.el.getElement('.prev').addClass('disabled');
    }
    this.el.getElement('.next').removeClass('disabled');
    return false;
  }
  
});

MoMA.Features = new Class({
  
  rotatePeriod: 3000, // Switch an item in the grid every 4.5 seconds
  overlayDelay: 500,
    
  initialize: function(el, page) {
    
    this.el = el;
    this.page = page;
    this.visible = {};
    this.queue = []; // Used to rotate between hidden items
    this.hovered = false;
    
    this.addItems(el);
    this.setupRotation();
    
    if (this.queue.length > 0) {
      page.addEvent('onInitialize', this.startRotation.bind(this));
    }
  },
  
  setupRotation: function() {
    // This keeps track of where to rotate next
    this.rotateNum = 0;
    this.positions = this.queue.map(function(item) {
      if ($type(item) == 'element') {
        item = item.retrieve('item');
      }
      return item.position;
    });
    this.positions = this.positions.unique();
    this.positions.shuffle();
  },
  
  addItems: function(base) {
    base.getElements('.feature').each(function(el) {
      var feature = this.generateItem(el);
      if (el.hasClass('visible') || feature.rotateImages) {
        this.visible[feature.position] = feature;
      }
    }.bind(this));
  },
  
  generateItem: function(el) {
    return new MoMA.Features.Item(el, this);
  },
  
  startRotation: function() {
    this.lastRotatedPosition = false;
    if (this.page.featuresPauseRotation) {
      // This allows a flash element to take precedence at load time
      this.rotateInterval = this.rotateVisible.periodical(this.rotatePeriod, this);
    } else {
      this.rotateInterval = this.rotateVisible.periodical(this.rotatePeriod, this);
    }
  },
  
  hoverShow: function(target) {
    this.hovered = target;
  },
  
  hoverHide: function() {
    this.hovered = false;
  },
  
  rotateVisible: function() {
    var nextItem = this.getNextVisible();
    if (!nextItem) {
      return;
    }
    var grid = nextItem.grid;
    // We need to count down to ensure we're not looping forever
    var countdown = grid.queue.length;
    while (grid.visible[nextItem.position].isHovered() && countdown > 0) {
      grid.queue.push(nextItem);
      nextItem = this.getNextVisible();
      countdown--;
    }
    nextItem.coords = grid.visible[nextItem.position].coords;
    nextItem.show();
    this.lastRotatedPosition = nextItem.position;
  },
  
  getNextVisible: function() {
    var nextPosition = this.positions[this.rotateNum % this.positions.length];
    var next = false;
    for (var i = 0; i < this.queue.length; i++) {
      next = this.queue[i];
      if ($type(next) == 'element') {
        next = next.retrieve('item');
      }
      if (this.qualifiesForNextRotation(next)) {
        this.queue.erase(next);
        break;
      } else {
        next = false;
      }
    }
    return next;
  },
  
  qualifiesForNextRotation: function(item) {
    var nextPosition = this.positions[this.rotateNum % this.positions.length];
    if (item.position == nextPosition && (!item.el.hasClass('visible') || item.rotateImages)) {
      this.rotateNum++;
      return true;
    }
    return false;
  }
  
});

MoMA.Features.Item = new Class({
  
  initialize: function(el, grid) {
    if (el && grid) {
      this.el = el;
      this.grid = grid;
      this.color = el.getStyle('background-color');
      
      this.setupCaption();
      this.setupOutline();
      this.setupFx();
      this.setupPosition();
      this.setupEvents();
      this.setupGridQueue();
      this.setupImageLinks();
      
      if (this.el.hasClass('visible')) {
        this.assumeTallestRowHeight();
      }
      
    }
  },
  
  setupCaption: function() {
    if (this.isSlidable()) {
      this.el.getElement('.holder').addClass('bottom-caption');
      this.hasBottomCaption = true;
      this.caption = this.el.getElement('.caption');
      this.caption.set('tween', {
        duration: 500,
        transition: Fx.Transitions.Quart.easeOut
      });
      if (this.el.hasClass('visible')) {
        this.resetFill();
      } else {
        this.el.removeClass('hidden');
        this.resetFill();
        this.el.addClass('hidden');
      }
    }
  },
  
  setupOutline: function() {
    if (this.el.getElement('.outlined')) {
      var outline = new Element('span', {
        'class': 'outline'
      });
      outline.inject(this.el.getElement('.holder'));
    }
  },
  
  setupFx: function() {
    this.colorFx = new Fx.Tween(this.el, {
      duration: 500,
      transition: Fx.Transitions.Quart.easeOut
    });
    this.opacityFx = new Fx.Tween(this.el, {
      duration: 1000,
      transition: Fx.Transitions.Quart.easeOut,
      onStart: function() {
        this.el.addClass('transition');
      }.bind(this),
      onComplete: function() {
        this.grid.visible[this.position].hide();
        this.grid.visible[this.position] = this;
        this.el.removeClass('transition');
        this.el.addClass('visible');
        if (this.delayedMouseOver) {
          this.delayedMouseOver = false;
          this.mouseOver();
        }
      }.bind(this)
    });
  },
  
  setupPosition: function() {
    var col = this.el.className.match(/col-(\S+)/)[1];
    var row = this.el.className.match(/row-(\S+)/)[1];
    this.position = col + ',' + row;
    if (this.el.hasClass('visible')) {
      this.coords = this.el.getCoordinates(this.grid.el);
      this.setupHoverFill();
    } else if (this.grid.visible[this.position]) {
      this.coords = this.grid.visible[this.position].coords;
    }
  },
  
  setupEvents: function() {
    if (!this.el.getElement('.no-hover')) {
      this.el.addEvent('mouseenter', this.mouseOver.bind(this));
      this.el.addEvent('mouseleave', this.mouseOut.bind(this));
      var hover = this.el.getElement('.hover');
      if (hover) {
        hover.setStyles({
          border: '2px solid ' + this.color,
          width: this.coords.width - 4,
          height: this.coords.height - 4
        });
      }
    } else {
      this.el.getElement('.hover').destroy();
      this.el.getElement('.fill').destroy();
    }
  },
  
  setupGridQueue: function() {
    var images = this.el.getElements('img');
    
    // Technically this shouldn't go here, but whatever
    images.each(function(img) {
      // For browsers that display alt attributes as a tool tip (IE only?)
      img.removeAttribute('alt');
    });
    
    // Either the whole item gets rotated, or just its images do
    if (this.el.hasClass('hidden')) {
      this.rotateImages = false;
      this.grid.queue.push(this);
    } else if (images.length > 1) {
      this.rotateImages = true;
      var initiallyVisible = $random(0, images.length - 1);
      images.each(function(img, num) {
        img.set('tween', {
          duration: 1000,
          transition: Fx.Transitions.Quart.easeOut,
          onComplete: function() {
            this.hide();
          }.bind(this)
        });
        img.store('item', this);
        if (num === initiallyVisible) {
          img.addClass('visible');
        } else {
          this.grid.queue.push(img);
          img.addClass('hidden');
        }
      }.bind(this));
    }
  },
  
  setupHoverFill: function() {
    if (this.hoverFillIsSetup) {
      return;
    }
    this.hoverFillIsSetup = true;
    if (this.isSlidable()) {
      this.resetFill();
    }
  },
  
  setupImageLinks: function() {
    var linkedImages = this.el.getElements('a img');
    if (linkedImages.length > 0) {
      // This is slightly hacky. Instead the hover should be an anchor by default
      var hover = this.el.getElement('.hover');
      hover.setStyle('cursor', 'pointer');
      hover.addEvent('click', function() {
        window.location = linkedImages[0].getParent('a').get('href');
        return false;
      });
    }
  },
  
  mouseOver: function() {
    if (this.el.hasClass('transition')) {
      this.delayedMouseOver = true;
      return;
    }
    this.grid.hoverShow(this);
    this.el.addClass('hovered');
    if (this.isSlidable()) {
      this.slideFill();
    } else if (!this.isIntroduction()) {
      this.colorFx.start('background-color', '#FFF');
    }
  },
  
  mouseOut: function(e) {
    this.grid.hoverHide();
    this.el.removeClass('hovered');
    if (this.isSlidable()) {
      this.resetFill();
    } else {
      this.colorFx.cancel();
      this.el.setStyle('background-color', this.color);
    }
  },
  
  isHovered: function() {
    return this.el.hasClass('hovered');
  },
  
  isIntroduction: function() {
    return (this.el.hasClass('size-6x4'));
  },
  
  isSlidable: function() {
    return (this.hasCaption() && this.isLargish());
  },
  
  isLargish: function() {
    return (this.el.hasClass('size-4x4') || this.el.hasClass('size-2x4'));
  },
  
  hasCaption: function() {
    return ($type(this.el.getElement('.caption')) == 'element');
  },
  
  slideFill: function() {
    this.el.getElement('.fill').setStyle('top', 0);
  },
  
  resetFill: function() {
    var fill = this.el.getElement('.fill');
    var caption = this.el.getElement('.caption');
    if (fill && caption) {
      fill.setStyle('top', this.el.getSize().y - caption.getSize().y);
    }
  },
  
  assumeTallestRowHeight: function() {
    var row = this.position.match(/.+,(\d+)$/)[1];
    var neighbors = $H(this.grid.visible).getKeys().filter(function(position) {
      return (position.substr(',' + row) !== -1);
    }.bind(this));
  },
  
  show: function() {
    if (!this.rotateImages) {
      this.el.setStyle('opacity', 0);
      this.el.removeClass('hidden');
      if (this.isSlidable()) {
        this.resetFill();
      }
      this.opacityFx.start('opacity', 1).chain(function() {
        this.setupHoverFill();
      }.bind(this));
      if (this.hasBottomCaption) {
        this.caption.setStyle('opacity', 0);
        this.el.getElement('.fill').setStyle('opacity', 0);
        this.showCaption.delay(this.grid.overlayDelay, this);
      }
    } else {
      var currImage = this.el.getElement('.visible');
      currImage.setStyle('z-index', 2);
      this.prevImage = currImage;
      
      var nextImage = currImage.getNext('.hidden');
      if (!nextImage) {
        nextImage = this.el.getElement('.hidden');
      }
      nextImage.setStyles({
        'z-index': 3,
        opacity: 0
      });
      nextImage.removeClass('hidden');
      nextImage.addClass('visible');
      nextImage.tween('opacity', 1);
    }
  },
  
  hide: function() {
    if (!this.rotateImages) {
      this.grid.queue.push(this);
      this.el.removeClass('visible');
      this.el.addClass('hidden');
    } else {
      this.prevImage.removeClass('visible');
      this.prevImage.addClass('hidden');
      this.grid.queue.push(this.prevImage);
    }
  },
  
  
  /* ------------------ SETS OPACITY FOR HORIZONTAL FEATURE OVERLAY --------- */
  /* ------------------ ALSO IN #features .bottom-caption .fill IN GLOBAL.CSS --------- */
  showCaption: function() {
    if (this.caption) {
      this.caption.tween('opacity', 1);
      this.el.getElement('.fill').tween('opacity', .6);
    }
  }
  
});


MoMA.HomeFeatures = new Class({
  
  Extends: MoMA.Features,
  
  overlayDelay: 2000,
  
  initialize: function(el, page) {
    this.parent(el, page);
    var initialPosition = this.positions[this.positions.length - 1];
    if (initialPosition != 'a,1' && this.visible[initialPosition].overlay) {
      this.visible[initialPosition].overlay.setStyle('opacity', 0);
      this.visible[initialPosition].showOverlay.delay(this.overlayDelay, this.visible[initialPosition]);
    }
  },
  
  generateItem: function(el) {
    if (el.hasClass('col-e') && el.hasClass('row-1')) {
      return new MoMA.HomeFeatures.TopRightItem(el, this);
    } else {
      return new MoMA.HomeFeatures.Item(el, this);
    }
  }
  
});


MoMA.HomeFeatures.Item = new Class({
  
  Extends: MoMA.Features.Item,
  
  initialize: function(el, grid) {
    this.parent(el, grid);
    this.overlay = this.el.getElement('.overlay');
    if (this.overlay) {
      this.overlay.set('tween', {
        duration: 1000,
        transition: Fx.Transitions.Quart.easeOut
      });
    }
    this.el.addEvent('mouseenter', this.showOverlay.bind(this));
    this.el.addEvent('mouseleave', this.hideOverlay.bind(this, true));
  },
  
  show: function() {
    if (this.overlay) {
      this.overlay.setStyle('opacity', 0);
      this.showOverlayDelay = this.showOverlay.delay(this.grid.overlayDelay, this);
    }
    (new MoMA.Features.Item()).show.run([], this);
  },
  
  showOverlay: function() {
    if (this.overlay) {
      if (this.showOverlayDelay) {
        $clear(this.showOverlayDelay);
      }
      if (this.grid.lastOverlayPosition && this.overlay) {
        var lastOverlay = this.grid.visible[this.grid.lastOverlayPosition];
        if (lastOverlay.el.hasClass('hovered')) {
          return;
        } else {
          lastOverlay.hideOverlay();
        }
      }
      this.grid.lastOverlayPosition = this.position;
      this.overlay.setStyle('background-color', this.color);
      this.overlay.tween('opacity', 1);
    }
  },
  
  hideOverlay: function(onMouseLeave) {
    if (this.overlay) {
      if (!onMouseLeave) {
        this.overlay.tween('opacity', 0);
      } else {
        this.overlay.tween('opacity', 1);
        this.overlay.setStyle('background-color', '#ffffff');
        this.overlay.tween('background-color', this.color);
      }
    }
  }
  
});

MoMA.HomeFeatures.TopRightItem = new Class({
  
  Extends: MoMA.HomeFeatures.Item,
  
  initialize: function(el, grid) {
    this.parent(el, grid);
  },
  
  resetFill: function() {
    var mainCaption = this.grid.visible['a,1'].el.getElement('.caption');
    this.caption.setStyle('height', mainCaption.getSize().y - 20);
    (new MoMA.Features.Item()).resetFill.run([], this);
  }
  
});


MoMA.MultiPage = new Class({
  
  initialize: function(el) {
    this.el = el;
    this.slider = el.getElement('.slider');
    this.slider.set('tween', {
      duration: 750,
      transition: Fx.Transitions.Quart.easeOut
    });
    el.getElements('.pages a').each(function(link) {
      link.addEvent('click', this.clickLink.bind(this));
    }.bind(this));
  },
  
  clickLink: function(e) {
    e = new Event(e);
    e.preventDefault();
    
    this.el.getElement('.pages .selected').removeClass('selected');
    $(e.target).addClass('selected');
    this.slider.tween('left', $(e.target).get('rel'));
  }
  
});

MoMA.Sharing = new Class({
  
  initialize: function(el) {
    this.el = el;
    $('share-link').addEvent('click', this.toggle.bind(this));
  },
  
  toggle: function() {
    this.el.toggleClass('visible');
    return false;
  }
  
});

MoMA.IntroMovie = new Class({
  
  initialize: function(el, page) {
    if (window.location.search.contains('noflash') ||
        window.location.hash.contains('txt') ||
        window.location.hash.contains('login') ||
        window.location.hash.contains('register') ||
        Browser.Plugins.Flash.version < 9 ||
        !this.browserIsSupported()) {
      page.fireEvent('introComplete');
      $('features').setStyle('visibility', 'visible');
      return;
    }
    if (this.hasSeenIntroMovie() && !window.location.search.contains('flash')) {
      $('features').setStyle('visibility', 'visible');
      return;
    }
    Cookie.write('hasSeenIntroMovie', 'yes', {
      duration: 24 / .1
    });
    $(document.body).addClass('intro-in-progress');
    page.featuresPauseRotation = true;
    this.el = el;
    this.page = page;
    this.setupFunctions();
    this.setupSwiff();
    this.setupEvents();
    /*$('top-nav').setStyles({
      opacity: 0,
      visibility: 'visible'
    });*/
  },
  
  hasSeenIntroMovie: function() {
    /*return false; // Disabled for now */
    return Cookie.read('hasSeenIntroMovie');
  },
  
  setupFunctions: function() {
    window.introComplete = function() {
      this.page.featuresPauseRotation = false;
      this.page.fireEvent('onIntroComplete');
    }.bind(this);
    window.introFade = function() {
      this.page.fireEvent('onIntroFade');
    }.bind(this);
  },
  
  setupSwiff: function() {
    var now = new Date();
    this.el.setStyle('width', '100%');
    this.swiff = new Swiff('/1.swf?' + now.getTime(), {
      width: '100%',
      height: 530,
      container: this.el
    });
  },
  
  setupEvents: function() {
    this.page.addEvent('onIntroComplete', function() {
      document.body.removeClass('intro-in-progress');
      $('top-nav').fade('in');
      this.el.destroy();
    }.bind(this));
    this.page.addEvent('onIntroFade', function() {
      $('features').setStyle('visibility', 'visible');
      document.body.removeClass('intro-in-progress');
    });
    window.addEvent('resize', function() {
      if (window.getSize().x < 1000) {
        this.el.setStyle('width', 1000);
      } else {
        this.el.setStyle('width', '100%');
      }
    }.bind(this));
  },
  
  browserIsSupported: function() {
    // Camino 1.6 has some weird issue with Flash
    return !(Browser.Engine.gecko && Browser.Engine.version < 19);
  }
  
});

MoMA.SectionTabs = new Class({
  
  initialize: function(el, page) {
    this.el = el;
    this.tabLinks = el.getElements('a');
    this.tabLinks.each(function(tabLink) {
      tabLink.addEvent('click', function(e) {
        e = new Event(e);
        var href = tabLink.get('href');
        var id = href.substr(href.indexOf('#') + 1);
        $$('.sectiontabs .selected')[0].removeClass('selected');
        $(e.target).addClass('selected');
        $$('.sectiontabs-content .selected')[0].removeClass('selected');
        $(id).addClass('selected');
        return false;
      });
    }.bind(this));
    this.page = page;
  }
  
});

MoMA.Collapsible = new Class({
  
  initialize: function(el, page) {
    this.el = el;
    this.page = page;
    
    var introModel = el.getElement('.intro');
    var introText = introModel.get('text');
    
    var titleLink = new Element('a', {
      href: '#',
      events: {
        click: this.toggle.bind(this)
      },
      styles: {
        outline: 'none'
      }
    });
    
    var titleModel = el.getElement('h4');
    var titleHeader = titleModel.clone();
    titleHeader.inject(titleLink);
    titleModel.destroy();
    
    titleLink.inject(el, 'top');
    
    var intro = new Element('span', {
      'class': 'excerpt',
      'text': introText
    });
    intro.inject(el);
    
    this.expander = new Element('a', {
      'href': '#',
      'text': '[+]',
      'class': 'expander',
      'events': {
        'click': this.toggle.bind(this)
      }
    });
    this.expander.inject(el);
    
    var details = el.getElement('.details');
    this.slide = new Fx.Slide(details).hide();
    details.setStyle('display', 'block');
    
    introModel.set('text', introText.replace('...', ''));
  },
  
  toggle: function() {
    this.el.toggleClass('expanded');
    if (this.expander.get('text') == '[+]') {
      this.expander.set('text', '[-]');
    } else {
      this.expander.set('text', '[+]');
    }
    this.slide.toggle();
    return false;
  }
  
});

MoMA.PerspectivesMenu = new Class({
  
  initialize: function(el, page) {
    el.addEvent('change', function() {
      window.location = el.options[el.selectedIndex].value;
    });
  }
  
});

MoMA.CollapsibleNav = new Class({
  
  initialize: function(el, page) {
    this.el = el;
    el.addEvent('mouseenter', this.showNav.bind(this));
    el.addEvent('mouseleave', this.hideNav.bind(this));
  },
  
  showNav: function() {
    this.el.fade('in');
  },
  
  hideNav: function() {
    this.el.fade('out');
  }
  
});

/*MoMA.DateInput = new Class({
  
  initialize: function(el, page) {
    this.el = el;
    new OverText([this.el]);
    this.picker = new DatePicker(this.el, {
      draggable: false,
      useDefaultCss: false,
      dayLabelLength: 1,
      groupNavLinks: true,
      wrapDayLinks: true,
      stickyWinOptions: {
        offset: {
          x: -10,
          y: 0
        },
        position: 'bottomLeft',
        className: 'datePicker'
      },
      stickyWinUiOptions: {
        css: '',
        cssClass: 'datePickerWindow'
      }
    });
  }
  
});*/

MoMA.Exhibitions = new Class({
  
  dayWidth: 5, /* Each day is 5 pixels wide */
  colors: ['#f0f0f0', '#7ac142'],
  labelHeight: 90,
  exhibitionHeight: 36,
  timelineHeight: 24,
  labelOffset: 14,
  
  highlightTitle: 'This week',
  highlightDays: 7,
  minSpan: ['month', 4],
  maxSpan: ['month', 6],
  
  initialize: function(el, page) {
    this.el = el;
    this.exhibitions = [];
    this.setupToday();
    this.setupTimespan();
    this.setupExhibitions();
    this.setupTimeline();
    this.arrangeExhibitions();
    this.replicateExhibitionTitles();
    this.highlight();
    $(document.body).addEvent('mousemove', this.moveHover.bind(this));
    window.exhibitions = this.exhibitions;
  },
  
  setupToday: function() {
    this.today = new Date().clearTime();
  },
  
  setupTimespan: function() {
    var origin = this.today.clone();
    this.min = origin.clone().decrement(this.minSpan[0], this.minSpan[1]).clearTime();
    this.max = origin.clone().increment(this.maxSpan[0], this.maxSpan[1] + 1).decrement('second', 1);
    this.dayRange = this.min.diff(this.max, 'day');
    this.timeRange = this.max.getTime() - this.min.getTime();
  },
  
  setupExhibitions: function() {
    this.el.getElements('.exhibition').each(function(el) {
      this.addExhibition(new this.Exhibition(el, this));
    }.bind(this));
    this.num = this.exhibitions.length;
  },
  
  setupTimeline: function() {
    
    this.exhibitionsHeight = this.num * this.exhibitionHeight;
    this.totalHeight = this.exhibitionsHeight + this.labelHeight + this.timelineHeight;
    
    var curr = this.min.clone();
    while (curr.diff(this.max, 'day') > 0) {
      var label = new Element('div', {
        text: this.getLabelTitle(curr),
        styles: {
          left: this.getPosition(curr) + 10
        }
      });
      label.inject($('timeline'));
      curr = this.addTickMark(curr);
    }
    curr = this.addTickMark(curr);
    
    $('timeline').setStyle('width', this.getPosition(this.max) + 20);
    this.totalWidth = this.getPosition(this.max, true);
    
    this.el.getElement('.holder').setStyles({
      width: this.totalWidth,
      height: this.totalHeight
    });
    this.el.getElement('.exhibitions-holder').setStyles({
      width: this.totalWidth,
      height: this.exhibitionsHeight
    });
    this.el.getElement('.backgrounds-holder').setStyles({
      width: this.totalWidth,
      height: this.exhibitionsHeight
    });
    
  },
  
  addTickMark: function(curr) {
    var tickMark = new Element('div', {
      'class': 'tick-mark',
      styles: {
        left: this.getPosition(curr, (curr.getMonth() == 2 && curr.getDate() == 3)),
        height: this.totalHeight - this.timelineHeight
      }
    });
    tickMark.inject(this.el.getElement('.holder'));
    return this.nextTickMark(curr);
  },
  
  nextTickMark: function(curr) {
    curr.set('date', 1);
    return curr.increment('month', 1);
  },
  
  addExhibition: function(exhibition) {
    var exhibitionCutoff = this.today.clone().decrement('week', 2);
    if (exhibition.start < this.min) {
      if (exhibition.end < this.min || exhibition.end < exhibitionCutoff) {
        exhibition.el.destroy();
        delete exhibition;
        return;
      }
      exhibition.start = this.min;
    }
    if (exhibition.end === false || exhibition.end > this.max) {
      if (exhibition.start > this.max) {
        exhibition.el.destroy();
        delete exhibition;
        return;
      }
      exhibition.end = this.max;
    }
    var background = new Element('div', {
      'class': 'background',
      styles: {
        background: this.colors[this.exhibitions.length % this.colors.length]
      }
    });
    background.inject(this.el.getElement('.backgrounds-holder'));
    exhibition.background = background;
    this.exhibitions.push(exhibition);
  },
  
  arrangeExhibitions: function() {
    this.exhibitions.each(function(exhibition, num) {
      var start = this.getPosition(exhibition.start, num == 5);
      var end = this.getPosition(exhibition.end);
      exhibition.el.setStyles({
        left: start,
        top: num * this.exhibitionHeight
      });
      exhibition.background.setStyles({
        left: start,
        top: num * this.exhibitionHeight,
        width: end - start
      });
    }.bind(this));
    this.el.addClass('enabled');
  },
  
  replicateExhibitionTitles: function() {
    this.exhibitions.each(function(exhibition) {
      exhibition.replicateTitle();
    });
  },
  
  highlight: function() {
    var position = this.getPosition(this.today);
    var highlight = new Element('div', {
      'class': 'highlight',
      styles: {
        left: position,
        width: this.highlightDays * this.dayWidth,
        height: this.exhibitionsHeight + 8
      }
    });
    highlight.inject(this.el.getElement('.holder'));
    var scroll = new Fx.Scroll(this.el);
    scroll.set(this.getPosition(this.today) - 25, 0);
    $('highlight-label-top').set('text', this.highlightTitle);
    $('highlight-label-top').setStyle('left', this.getPosition(this.today) - this.labelOffset);
    $('highlight-label-bottom').setStyle('left', this.getPosition(this.today) - this.labelOffset);
    $('highlight-label-bottom').set('text', this.highlightTitle);
  },
  
  getLabelTitle: function(date) {
    var monthTitles = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                       'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    return monthTitles[date.getMonth()] + ' ' +
           date.getFullYear().toString();
  },
  
  getPosition: function(date, interesting) {
    if (date === false) {
      date = this.max;
    }
    var total = this.dayRange * this.dayWidth;
    var pos = total * (date.getTime() - this.min.getTime()) / this.timeRange;
    return pos;
  },
  
  moveHover: function(e) {
    if (!this.hoverTarget) {
      return;
    }
    e = new Event(e);
    var height = $('hover').getSize().y;
    if (!height) {
      $('hover').setStyles({
        display: 'block',
        visibility: 'hidden',
        opacity: 0
      });
      height = $('hover').getSize().y;
      if (Browser.Engine.name != 'trident') {
        $('hover').fade('in');
      }
    }
    height = Math.max(height, 108);
    if (this.setHoverOrientation(e)) {
      $('hover').setStyles({
        display: 'block',
        visibility: 'visible',
        top: e.page.y - height - 24,
        left: e.page.x - $('page').getPosition().x - 5
      });
    } else {
      $('hover').setStyles({
        display: 'block',
        top: e.page.y - height - 24,
        left: e.page.x - $('page').getPosition().x - 5 - 370
      });
    }
  },
  
  setHoverOrientation: function(e) {
    if (e.page.x + 385 > window.getSize().x) {
      $('hover').addClass('left');
      return false;
    } else {
      $('hover').removeClass('left');
      return true;
    }
  },
  
  daysInMonth: function(date) {
    return 32 - new Date(date.getFullYear(), date.getMonth(), 32).getDate();
  },
  
  Exhibition: new Class({
    
    initialize: function(el, controller) {
      this.el = el;
      this.controller = controller;
      this.hover = el.clone();
      this.parseWhen();
      el.getElement('a').addEvent('mouseenter', this.showHover.bind(this));
      el.getElement('a').addEvent('mouseleave', this.hideHover.bind(this));
      this.hover.inject($('hover').getElement('.content'));
    },
    
    parseWhen: function(when) {
      var start = this.el.getElement('.start').get('text');
      var end = this.el.getElement('.end').get('text');
      if (end === '') {
        end = false;
      } else if (start == end) {
        end = Date.parse(parseInt(end) * 1000).increment('day', 1);
      } else {
        end = Date.parse(parseInt(end) * 1000);
      }
      this.start = Date.parse(parseInt(start) * 1000);
      this.end = end;
      this.start.clearTime();
      if (this.end) {
        this.end.clearTime();
      }
    },
    
    replicateTitle: function() {
      var link = this.el.getElement('h3 a');
      var span = link.getElement('span');
      var replicaWidth;
      if (span.getSize().x < this.background.getSize().x) {
        link.setStyle('width', this.background.getSize().x);
        for (var replica, w = span.getSize().x; w < link.getSize().x; w += replicaWidth) {
          replica = span.clone();
          replica.addClass('replica');
          replica.inject(link);
          replicaWidth = replica.getSize().x + parseInt(replica.getStyle('margin-left'));
        }
      }
      var clear = new Element('br', {
        'class': 'clear'
      });
      clear.inject(link);
    },
    
    showHover: function() {
      this.hover.setStyle('display', 'block');
      this.controller.hoverTarget = this;
      $('hover').fade('in');
    },
    
    hideHover: function(e) {
      this.hover.setStyle('display', 'none');
      if (this.controller.hoverTarget == this) {
        this.controller.hoverTarget = false;
      }
      $('hover').setStyle('display', 'none');
    }
    
  })
  
});

MoMA.FilmExhibitions = new Class({
  
  dayWidth: 137,
  labelOffset: 0,
  highlightDays: 1,
  highlightTitle: 'Today',
  minSpan: ['day', 15],
  maxSpan: ['day', 15],
  
  Extends: MoMA.Exhibitions,
  
  setupToday: function() {
    this.today = new Date().clearTime();
  },
  
  getLabelTitle: function(date) {
    var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    return days[date.getDay()] + ', ' + months[date.getMonth()] + ' ' + date.getDate();
  },
  
  nextTickMark: function(curr) {
    return curr.increment('day', 1).clearTime();
  }
  
});

MoMA.MainNavigation = new Class({
  
  initialize: function(el, controller) {
    el.getElements('a.menu').each(function(link) {
      link.addEvent('mouseover', function(e) {
        if (this.waiting) {
          $clear(this.waiting);
        }
        this.waiting = this.linkOver.delay(200, this, e);
      }.bind(this));
      link.addEvent('mouseout', this.linkOut.bind(this));
      var menu = $(link.get('rel'));
      if (menu) {
        menu.addEvent('mouseleave', this.menuOut.bind(this));
      }
    }.bind(this));
  },
  
  linkOver: function(e) {
    e = new Event(e);
    this.waiting = false;
    var id = $(e.target).get('rel');
    var subnav = $(id);
    if (subnav) {
      this.visibleMenu = id;
      if (id == 'subnav-ps1') {
        subnav.setStyles({
          display: 'block'
        });
      } else {
        subnav.setStyles({
          display: 'block',
          left: $(e.target).getPosition($$('#nav .relative')[0]).x
        });
      }
      if ($(e.target).parentNode) {
        $(e.target.parentNode).addClass('open');
      }
      subnav.getElement('.left').setStyle('height', subnav.getSize().y);
      
    }
  },
  
  linkOut: function(e) {
    e = new Event(e);
    var id = $(e.target).get('rel');
    var subnav = $(id);
    if (this.waiting) {
      $clear(this.waiting);
    }
    if (!subnav) {
      return;
    }
    if (e.relatedTarget && subnav.hasChild(e.relatedTarget)) {
      return;
    }
    subnav.setStyle('display', 'none');
    if (e.target.parentNode) {
      $(e.target.parentNode).removeClass('open');
    }
  },
  
  menuOut: function(e) {
    if (e.relatedTarget &&
        $(e.relatedTarget).get('rel') &&
        $(e.relatedTarget).get('rel') == this.visibleMenu) {
      return;
    }
    $(this.visibleMenu).setStyle('display', 'none');
    var open = $$('#nav .open');
    if (open.length !== 0) {
      open[0].removeClass('open');
    }
  }
  
});

MoMA.Tribute = new Class({
  
  initialize: function(el) {
    /*this.slide = new Fx.Slide($('tribute-details'), {
      duration: 1000
    });
    if ($('honor_flag_y').checked) {
      $('tribute').addClass('visible');
      this.slide.show();
    } else {
      $('tribute').removeClass('visible');
      this.slide.hide();
    }
    this.el = el;
    */
    $('honor_flag_y').addEvent('click', this.onChange.bind(this));
    $('honor_flag_n').addEvent('click', this.onChange.bind(this));
    if ($('honor_flag_y').checked) {
      $('tribute').addClass('visible');
    } else {
      $('tribute').removeClass('visible');
    }
  },
  
  onChange: function() {
    /*
    if ($('tribute').hasClass('visible')) {
      this.slide.toggle().chain(function() {
        $('tribute').toggleClass('visible');
      });
    } else {
      $('tribute').toggleClass('visible');
      this.slide.toggle();
    }
    */
    if ($('honor_flag_y').checked) {
      $('tribute').addClass('visible');
    } else {
      $('tribute').removeClass('visible');
    }
  }
  
});

MoMA.SocialBar = new Class({
  
  initialize: function(el) {
    this.expanded = false;
    $('social').set('tween', {
      duration: 500,
      transition: Fx.Transitions.Quint.easeOut
    });
    el.addEvent('click', function() {
      if (!this.expanded) {
        $('social').setStyle('background-image', 'none');
        $('social').tween('height', 300);
      } else {
        $('social').setStyle('background-image', 'url(/new/images/nav/perspectives.png)');
        $('social').tween('height', 25);
      }
      this.expanded = !this.expanded;
    }.bind(this));
  }
  
});

MoMA.MembershipOptions = new Class({
  
  initialize: function(el) {
    this.el = el;
    this.setupCategories();
    this.setupMemberInfo();
  },
  
  setupCategories: function() {
    var links = this.el.getElements('.option a');
    var details = this.el.getElements('.option .details');
    this.accordion = new Accordion(links, details, {
      start: 'all-close',
      onActive: function(toggler, element) {
        if (this.active) {
          this.active.setStyle('height', $(this.active).getSize().y);
        }
        this.active = $(element);
        return false;
      }.bind(this),
      onComplete: function() {
        this.active.setStyle('height', 'auto');
      }.bind(this)
    });
    
    if (this.el.getElement('.gift').hasClass('selected') &&
        this.el.getElement('.message')) {
      this.el.getElement('.message').fade('hide');
    }
    
    links.each(function(link) {
      link.addEvent('click', this.chooseOption.bind(this));
    }.bind(this));
    details.each(function(details) {
      details.addClass('visible');
    }.bind(this));
  },
  
  setupMemberInfo: function() {
    var slide = new Fx.Slide(this.el.getElement('.member-info'));
    if (!$('member-checkbox').checked) {
      slide.hide();
    }
    $('member-checkbox').addEvent('click', function() {
      slide.toggle();
    });
  },
  
  chooseOption: function(e) {
    e = new Event(e);
    if ($(e.target.parentNode).hasClass('me')) {
      $('membership_type').value = 'self';
      if (this.el.getElement('.message')) {
        this.el.getElement('.message').fade('in');
      }
    } else {
      $('membership_type').value = 'gift';
      if (this.el.getElement('.message')) {
        this.el.getElement('.message').fade('out');
      }
    }
    return false;
  }
  
});

MoMA.MembershipCategories = new Class({
  
  initialize: function(el) {
    el.getElements('.category').each(function(category) {
      var slide = new Fx.Slide(category.getElement('.benefits'));
      slide.hide();
      category.getElement('.expand').addEvent('click', function() {
        slide.toggle();
        return false;
      });
      category.getElement('.collapse').addEvent('click', function() {
        slide.toggle();
        return false;
      });
    });
  }
  
});

MoMA.TabbedContent = new Class({
  
  initialize: function(el) {
    this.el = el;
    el.getElement('.tabs a').addClass('selected');
    el.getElement('.pane').addClass('selected');
    el.getElements('.tabs a').each(function(link) {
      link.addEvent('click', this.onClick.bind(this));
    }.bind(this));
    if (window.location.hash && window.location.hash !== '') {
      this.select(this.getHashId());
    } else {
      this.select(this.getTabId(el.getElement('.tabs a')));
    }
    this.minHeight = el.getElement('.tabs').getSize().y;
    this.checkHeight();
    this.checkURL.periodical(100, this);
  },
  
  checkURL: function() {
    var hashId = this.getHashId();
    if (hashId && this.currentId != hashId) {
      this.select(hashId);
    }
  },
  
  onClick: function(event) {
    this.select(this.getTabId(event.target));
  },
  
  select: function(id) {
    this.currentId = id;
    this.el.getElement('a.selected').removeClass('selected');
    this.el.getElement('div.selected').removeClass('selected');
    this.el.getElement('a.' + id).addClass('selected');
    this.el.getElement('div.' + id).addClass('selected');
    this.checkHeight();
  },

  checkHeight: function() {
    var pane = this.el.getElement('div.selected');
    if (pane.getSize().y < this.minHeight) {
      pane.setStyle('height', this.minHeight - 28);
    }
  },

  getTabId: function(el) {
    return el.get('href').match(/#(.+)/)[1];
  },

  getHashId: function() {
    if (!window.location.hash || window.location.hash === '') {
      return;
    }
    var hashId = window.location.hash;
    if (hashId.substr(0, 1) == '#') {
      hashId = hashId.substr(1);
    }
    return hashId;
  }

});

MoMA.Ticker = new Class({

  period: 4500,
  
  initialize: function(el) {
    this.el = el;
    if (!el.getElement('.selected')) {
      el.getElement('li').addClass('selected');
    }
    this.interval = setInterval(this.rotate.bind(this), this.period);
  },
  
  rotate: function() {
    var curr = this.el.getElement('.selected');
    if (!curr) {
      return;
    }
    var next = curr.getNext('li');
    if (!next) {
      next = this.el.getElement('li');
    }
    curr.fade('out').retrieve('tween').chain(function() {
      curr.removeClass('selected');
      next.fade('hide');
      next.addClass('selected');
      next.fade('in');
    });
  }

});

MoMA.MediaPlayer = new Class({
  
  autoPlay: 'true',
  playerId: 'media-player',
  width: 384,
  height: 288,
  
  initialize: function(el, page) {
    this.page = page;
    page.player = this;
    window.player = this;
    var assetLink = el.getElement('a.asset');
    var imageLink = el.getElement('a.image');
    var imageURL = false;
    if (imageLink && imageLink.get('href') != '#' && imageLink.get('href') != '') {
      imageURL = imageLink.get('href');
    }
    this.assetURL = assetLink.get('href');
    this.element = el;
    this.setupShare();
    if (window.location.search.contains('noflash')) {
      return;
    }
    try {
      this.swiff = new Swiff('/flash/media_player.swf', {
        id: this.playerId,
        width: this.width,
        height: this.height,
        container: el.getElement('.swiff'),
        params: {
          wMode: 'opaque',
          allowFullScreen: 'true',
          allowScriptAccess: 'always'
        },
        vars: {
          assetURL: this.assetURL,
          imageURL: imageURL,
          linkURL: 'http://www.moma.org/explore/multimedia/',
          enableAutoplay: this.autoPlay,
          showControls: 'true',
          enableFullscreen: 'true',
          enableKeys: 'true',
          enableMenu: 'true',
          menuTitle: 'MoMA Multimedia',
          bufferSeconds: '5',
          userIdle: '3000',
          volume: '50',
          logger: 'false',
          monitor: 'false',
          isReady: 'player.isReady',
          onComplete: 'player.onComplete',
          onPause: 'player.onPause',
          onResume: 'player.onResume',
          onPlay: 'player.onPlay',
          onError: 'player.onError',
          onFullscreen: 'player.onFullscreen',
          onVolumeChange: 'player.onVolumeChange'
        }
      });
    } catch (e) {
      // IE 7 is throwing an error in the Swiff call, even with try / catch
    }
  },

  onComplete: function() {
    // dbug.log('MediaPlayer.onComplete');
    this.page.playlist.playNextItem();
  },

  onError: function(error) {
    dbug.log(error);
  },

  isReady: $empty,
  onPause: $empty,
  onResume: $empty,
  onPlay: $empty,
  onFullscreen: $empty,
  onVolumeChange: $empty,
  play: $empty,

  setupShare: function() {
    var form = this.element.getElement('.share');
    if (!form) {
      return;
    }
    form.addEvent('submit', function() {
      return false;
    });
    form.getElements('a').each(function(link) {
      link.addEvent('click', function() {
        form.getElement('a.selected').removeClass('selected');
        form.getElement('input.selected').removeClass('selected');
        $(link.get('rel')).addClass('selected');
        link.addClass('selected');
        return false;
      }.bind(this));
    }.bind(this));
    
    if ($('permalink')) {
      $('permalink').addEvent('click', function() {
        setTimeout(function() {
          $('permalink').select();
        }, 0);
      });
    }
    
    if ($('embed')) {
      $('embed').addEvent('click', function() {
        setTimeout(function() {
          $('embed').select();
        }, 0);
        return false;
      });
    }
  }

});


MoMA.MediaPlayerLarge = new Class({
  
  Extends: MoMA.MediaPlayer,
  
  autoPlay: 'false',
  
  onPlay: function() {
    this.page.playlist.showPlaying(this.assetURL);
  }
  
});


MoMA.MediaPlayerMed = new Class({

  Extends: MoMA.MediaPlayer,
  
  playerId: 'media-player-medium',
  autoPlay: 'false'

});


MoMA.MediaPlayerSmall = new Class({
  
  Extends: MoMA.MediaPlayer,
  
  playerId: 'media-player-small',
  autoPlay: 'false',
  width: 205,
  height: 163
  
});


MoMA.MediaPlaylistSmall = new Class({
  
  initialize: function(el, page) {
    this.el = el;
    this.page = page;
    page.playlist = this;
    this.setupArrows();
    
  },
  
  setupArrows: function() {
    var arrows = $$('#containerMM .arrows a');
    if (arrows.length < 2) {
      return;
    }
    arrows[0].addEvent('click', this.playPreviousItem.bind(this));
    arrows[1].addEvent('click', this.playNextItem.bind(this));
  },
  
  playPreviousItem: function() {
    var selected = this.el.getElement('.selected');
    var previous = selected.getPrevious('li');
    if (!previous) {
      previous = this.el.getElements('li').getLast();
    }
    selected.removeClass('selected');
    this.playItem(previous);
    return false;
  },
  
  playNextItem: function() {
    var selected = this.el.getElement('.selected');
    var next = selected.getNext('li');
    if (!next) {
      next = this.el.getElement('li');
    }
    selected.removeClass('selected');
    this.playItem(next);
    return false;
  },
  
  playItem: function(item) {
    item.addClass('selected');
    var link = item.getElement('a');
    var title = $$('#containerMM .title');
    if (title.length > 0) {
      title[0].set('html', link.get('html'));
    }
    this.page.player.swiff.toElement().load(link.get('href'));
  }
  
});


MoMA.MediaPlaylist = new Class({
  
  initialize: function(el, page) {
    this.page = page;
    this.element = el;
    page.playlist = this;
    this.setupTabs();
    this.setupItems();
    this.selectPlaying();
  },
  
  setupTabs: function() {
    if (this.element.getElements('.tabs a').length === 0) {
      $('playlist').addClass('hide');
      return;
    }
    this.element.getElements('.tabs a').each(function(link) {
      link.addEvent('click', function(e) {
        e = new Event(e);
        return this.selectTab($(e.target).get('rel'));
      }.bind(this));
    }.bind(this));
    var first = this.element.getElements('.tabs a')[0];
    this.setScrollerHeight(first.get('rel'));
  },
  
  setupItems: function() {
    var items = this.element.getElements('a.media');
    items.each(function(link) {
      link.addEvent('click', function(e) {
        return this.playItem(link);
      }.bind(this));
      var status = new Element('span', {
        'class': 'status',
        'text': 'PLAYING'
      });
      status.inject(link);
    }.bind(this));
  },
  
  playItem: function(link) {
    if (link.get('href').contains('/interactives/')) {
      return true;
    }
    this.element.getElements('.playing').removeClass('playing');
    link.addClass('playing');
    try {
      var assetURL = link.get('rel');
      if (assetURL.contains(',')) {
        var assetParts = assetURL.split(',');
        assetURL = assetParts[0];
        imageURL = assetParts[1];
        window.player.swiff.toElement().load(assetURL, imageURL);
      } else {
        window.player.swiff.toElement().load(assetURL);
      }
      this.updatePlayerInfo(link);
    } catch(e) {
      dbug.log(e.message);
    }
    return false;
  },
  
  updatePlayerInfo: function(link) {
    var info = window.player.element.getElement('.info');
    info.set('html', '<div class="player-loading">Loading...</div>');
    var request = new Request({
      method: 'get',
      url: link.get('href').replace('/explore/multimedia', '/explore/multimedia/info'),
      onComplete: function(response) {
        info.set('html', response);
        window.player.setupShare();
      }
    });
    request.send();
  },
  
  playNextItem: function() {
    var curr = this.element.getElement('.playing');
    curr.removeClass('playing');
    if (curr) {
      var next = curr.getNext('a.media');
      if (next) {
        this.playItem(next);
      }
    }
  },
  
  selectTab: function(id) {
    if (!$(id)) {
      return false;
    }
    this.element.getElements('div.selected').removeClass('selected');
    $(id).addClass('selected');
    var selectedSearch = $$('.tabs .selected');
    if (selectedSearch.length > 0) {
      selectedSearch[0].removeClass('selected');
    }
    var tabSearch = $$(".tabs a[rel='" + id + "']");
    if (tabSearch.length > 0) {
      tabSearch[0].addClass('selected');
    }
    this.setScrollerHeight(id);
    return false;
  },
  
  setScrollerHeight: function(id) {
    var height = $(id).getSize().y;
    var title = $(id).getElement('h3');
    if (title) {
      height -= title.getSize().y;
    }
    if ($(id).getElement('.scrollable')) {
      $(id).getElement('.scrollable').setStyle('height', height);
    }
  },
  
  selectPlaying: function(url) {
    var assetURL = false;
    if (!url) {
      var asset = $$('#player .content a.asset');
      if (asset.length > 0) {
        var assetURL = asset[0].get('href');
      }
    } else {
      assetURL = url;
    }
    if (assetURL) {
      var item = this.element.getElement('a[rel=' + assetURL + ']');
      if (item) {
        item.addClass('playing');
      }
    }
  }
  
});

MoMA.MediaPlaylistMed = new Class({
  
  Extends: MoMA.MediaPlaylist,
  
  initialize: function(el, page) {
    this.parent(el, page);
    this.setupPageControls();
    this.shortenTitles();
  },
  
  setupPageControls: function() {
    this.currPage = 0;
    var prev = this.element.getElement('.controls .prev');
    var next = this.element.getElement('.controls .next');
    prev.addEvent('click', this.prevPage.bind(this));
    next.addEvent('click', this.nextPage.bind(this));
    this.element.getElement('.slider').set('tween', {
      duration: 350
    });
    if (this.element.getElements('.selected ol').length > 2) {
      //dbug.log(this.element.getElements('.selected ol'));
      this.element.getElement('.controls').addClass('show');
    }
  },
  
  shortenTitles: function() {
    if ($('tab-related')) {
      var revertRelated = $('tab-related').expose();
    }
    this.element.getElements('.info h4').each(function(h4) {
      if (h4.getParent('#tab-related')) {
        h4.shorten(60);
      } else {
        h4.shorten(65);
      }
    });
    if ($('tab-related')) {
      revertRelated();
    }
  },
  
  prevPage: function(e) {
    e = new Event(e);
    var link = $(e.target);
    if (link.hasClass('disabled')) {
      return false;
    }
    this.element.getElement('.controls .next').removeClass('disabled');
    this.currPage--;
    var lists = this.element.getElements('ol');
    if (this.currPage === 0) {
      link.addClass('disabled');
    }
    this.updatePageView();
    return false;
  },
  
  nextPage: function(e) {
    e = new Event(e);
    var link = $(e.target);
    if (link.hasClass('disabled')) {
      return false;
    }
    this.element.getElement('.controls .prev').removeClass('disabled');
    this.currPage++;
    var lists = this.element.getElements('ol');
    if (this.currPage == lists.length - 2) {
      link.addClass('disabled');
    }
    this.updatePageView();
    return false;
  },
  
  updatePageView: function() {
    var slider = this.element.getElement('.slider');
    var lists = this.element.getElements('ol');
    var list = lists[this.currPage];
    slider.tween('left', -(list.getPosition(slider).x + 1));
  },
  
  updatePlayerInfo: function() {
    var download = '';
    var title = this.element.getElement('a.playing .info h4').get('html');
    var link = this.element.getElement('a.playing');
    if (link.get('rel').contains('.mp3')) {
      var url = link.get('rel').match(/\/audio_file.+\.mp3/)[0];
      var download = '&nbsp;&nbsp;<a href="' + url + '"><small>Download</small></a>';
    }
    $('player-medium').getElement('.info p').set('html', title + download);
  }
  
});

MoMA.MediaChannels = new Class({
  
  initialize: function(el, page) {
    this.element = el;
    this.currGroup = 'group-0';
    this.setupItems();
    this.setupBack();
    this.page = page;
    page.channels = this;
    page.addEvent('onInitialize', this.clickSelected.bind(this));
  },
  
  clickSelected: function() {
    var selected = this.element.getElement('a.selected');
    if (!selected.hasClass('featured') && !selected.hasClass('most-recent')) {
      this.element.getElement('.back').removeClass('disabled');
      var list = selected.getParent('ol');
      list.addClass('selected');
      this.currGroup = list.get('id');
    }
    this.clickItem(selected, true);
  },
  
  setupItems: function() {
    this.element.getElements('.holder a').each(function(link) {
      link.addEvent('click', function() {
        this.clickItem(link);
        return false;
      }.bind(this));
    }.bind(this));
    this.element.getElement('.slider').set('tween', {
      duration: 275,
      onComplete: this.finishLoading.bind(this)
    });
  },
  
  clickItem: function(link, initialClick) {
    var slider = this.element.getElement('.slider');
    this.selectItem(link);
    this.page.packages.showLoadingMessage();
    if (link.get('rel') && $(link.get('rel'))) {
      var group = $(link.get('rel'));
      this.currGroup = link.get('rel');
      group.addClass('selected');
      this.linkClicked = link;
      this.isNewContext = true;
      if (initialClick === true) {
        slider.setStyle('left', -(group.getPosition(slider).x));
        this.finishLoading();
      } else {
        slider.tween('left', -(group.getPosition(slider).x));
      }
    } else {
      this.linkClicked = link;
      this.finishLoading();
      if (initialClick === true) {
        slider.setStyle('left', -(link.getPosition(slider).x));
      }
    }
  },
  
  selectItem: function(link) {
    var list = link.getParent('ol');
    list.getElements('a.selected').removeClass('selected');
    list.getElements('ol.selected').removeClass('selected');
    link.addClass('selected');
  },
  
  finishLoading: function() {
    
    if (!this.linkClicked) {
      return;
    }
    var link = this.linkClicked;
    this.linkClicked = false;
    
    if (link.hasClass('featured')) {
      this.element.getElement('.title').set('text', 'Select');
    } else {
      this.element.getElement('.title').set('text', link.get('text'));
    }
    
    if (this.isNewContext) {
      this.isNewContext = false;
      if (link.hasClass('featured')) {
        this.updatePackages(link);
      } else {
        this.clickItem($(this.currGroup).getElement('a'));
        this.element.getElement('.back').removeClass('disabled');
      }
    } else {
      this.updatePackages(link);
    }
  },
  
  updatePackages: function(link) {
    this.page.packages.setBreadCrumbs(link);
    var href = link.get('href').match(/#(.+)$/);
    if (href && href.length === 2) {
      this.page.packages.showChannel(href[1]);
    }
  },
  
  reset: function() {
    this.clickItem(this.element.getElement('.featured'));
  },
  
  setupBack: function() {
    var back = this.element.getElement('.back');
    var slider = this.element.getElement('.slider');
    back.addEvent('click', function() {
      var left = parseInt(slider.getStyle('left'), 10);
      if (left === 0) {
        return false;
      }
      this.isNewContext = true;
      slider.tween('left', left + 243).retrieve('tween').chain(function() {
        $(this.currGroup).removeClass('selected');
        this.currGroup = $(this.currGroup).getParent('ol').get('id');
        $(this.currGroup).getElement('.selected').removeClass('selected');
        //dbug.log('Clicking ' + $(this.currGroup).getElement('a').get('text'));
        this.clickItem($(this.currGroup).getElement('a'));
        if (this.currGroup == 'group-0') {
          this.element.getElement('.back').addClass('disabled');
        }
      }.bind(this));
      return false;
    }.bind(this));
  },
  
  getGroupLink: function(rel) {
    //dbug.log(rel);
    return this.element.getElement("a[rel='" + rel + "']");
  }
  
});

MoMA.MediaPackages = new Class({
  
  initialize: function(el, page) {
    this.page = page;
    this.element = el;
    page.packages = this;
    this.setupPageControls();
  },
  
  setupPageControls: function() {
    var prev = this.element.getElement('.controls .prev');
    var next = this.element.getElement('.controls .next');
    prev.addEvent('click', this.prevPage.bind(this));
    next.addEvent('click', this.nextPage.bind(this));
    this.element.getElement('.slider').set('tween', {
      duration: 350
    });
    this.element.getElement('.breadcrumbs a').addEvent('click', function() {
      return false;
    });
  },
  
  prevPage: function(e) {
    e = new Event(e);
    var link = $(e.target);
    if (link.hasClass('disabled')) {
      return false;
    }
    this.element.getElement('.controls .next').removeClass('disabled');
    this.currPage--;
    var lists = this.element.getElements('.selected ol');
    if (this.currPage === 0) {
      link.addClass('disabled');
    }
    this.updatePageView();
    return false;
  },
  
  nextPage: function(e) {
    e = new Event(e);
    var link = $(e.target);
    if (link.hasClass('disabled')) {
      return false;
    }
    this.element.getElement('.controls .prev').removeClass('disabled');
    this.currPage++;
    var lists = this.element.getElements('.selected ol');
    if (this.currPage == lists.length - 3) {
      link.addClass('disabled');
    }
    this.updatePageView();
    return false;
  },
  
  updatePageView: function() {
    var slider = this.element.getElement('.slider');
    var lists = this.element.getElements('.selected ol');
    var list = lists[this.currPage];
    slider.tween('left', -(list.getPosition(slider).x + 1));
  },
  
  showPageControls: function() {
    this.element.getElement('.controls').addClass('show');
  },
  
  hidePageControls: function() {
    this.element.getElement('.controls').removeClass('show');
  },
  
  setBreadCrumbs: function(link) {
    //dbug.log('setBreadCrumbs', link);
    var crumbs = this.element.getElement('.breadcrumbs');
    crumbs.removeClass('loading');
    crumbs.set('html', '');
    if (link && !link.hasClass('featured')) {
      //dbug.log(0);
      if (!link.hasClass('default')) {
        //dbug.log(1);
        this.addBreadCrumb(link);
      }
      while (link.getParent('ol')) {
        //dbug.log(2);
        var list = link.getParent('ol');
        //dbug.log(list);
        if (list.get('id') == 'group-0') {
          //dbug.log(2.1);
          break;
        }
        if (!link.hasClass('default')) {
          var separator = new Element('span', {
            html: '&nbsp;&gt;&nbsp;'
          });
          separator.inject(crumbs, 'top');
        }
        //dbug.log(2.2);
        link = this.page.channels.getGroupLink(list.get('id'));
        //dbug.log(link);
        this.addBreadCrumb(link);
      }
      var finalSeparator = new Element('span', {
        html: '&nbsp;&gt;&nbsp;'
      });
      finalSeparator.inject(crumbs, 'top');
    }
    var topLevel = new Element('a', {
      href: '#',
      html: 'Multimedia',
      events: {
        click: function() {
          this.page.channels.reset();
          return false;
        }.bind(this)
      }
    });
    topLevel.inject(crumbs, 'top');
  },
  
  showChannel: function(id) {
    if ($(id)) {
      this.setupChannel(id);
    } else {
      this.loadChannel(id);
    }
  },
  
  loadChannel: function(id) {
    this.loadingChannel = id;
    var request = new Request({
      url: '/explore/multimedia/channel/' + id,
      method: 'get',
      onComplete: function(html) {
        var slider = this.element.getElement('.slider');
        var existing = slider.get('html');
        slider.set('html', existing + html);
        this.setupChannel(id);
        this.setupChannelControls(id);
      }.bind(this)
    });
    request.send();
  },
  
  setupChannelControls: function(id) {
    var target = $(id);
    var slider = this.element.getElement('.slider');
    var width = 0;
    var lists = target.getElements('ol');
    this.currPage = 0;
    this.element.getElement('.slider').setStyle('left', 0);
    lists.each(function(list) {
      width += list.getSize().x;
    });
    slider.setStyle('width', width);
    if (lists.length > 3) {
      this.showPageControls();
    } else {
      this.hidePageControls();
    }
    target.getElements('.package').each(function(link) {
      link.getElement('h4').shorten(60);
    }.bind(this));
  },
  
  setupChannel: function(id) {
    if (!id && this.loadingChannel) {
      id = this.loadingChannel;
      this.loadingChannel = false;
    }
    var holder = this.element.getElement('.holder');
    holder.getElement('.slider').setStyle('opacity', 1.0);
    holder.removeClass('loading');
    this.element.getElement('.controls .prev').addClass('disabled');
    this.element.getElement('.controls .next').removeClass('disabled');
    this.element.getElements('.selected').removeClass('selected');
    $(id).addClass('selected');
  },
  
  showLoadingMessage: function() {
    var holder = this.element.getElement('.holder');
    holder.getElement('.slider').setStyle('opacity', 0.5);
    holder.addClass('loading');
  },
  
  addBreadCrumb: function(link) {
    var crumbs = this.element.getElement('.breadcrumbs');
    var crumb = new Element('a', {
      href: '#',
      text: link.get('text'),
      rel: link.get('rel'),
      events: {
        click: function(e) {
          e = new Event(e);
          var rel = $(e.target).get('rel');
          var channels = this.page.channels;
          var link = channels.getGroupLink(rel);
          channels.clickItem(link);
          return false;
        }.bind(this)
      }
    }).inject(crumbs, 'top');
  }
  
});

MoMA.SearchForm = new Class({

  initialize: function(el) {
    var input = el.getElement('.input');
    var button = el.getElement('.button');
    input.addEvent('focus', function() {
      input.addClass('focus');
    });
    input.addEvent('blur', function() {
      if (input.value === '') {
        input.removeClass('focus');
      }
    });
    button.addEvent('mouseenter', function() {
      button.addClass('button-hover');
    });
    button.addEvent('mouseleave', function() {
      button.removeClass('button-hover');
    });
    if (input.value !== '') {
      input.addClass('focus');
    }
  }
  
});

MoMA.ImageCaption = new Class({
  
  initialize: function(el) {
    this.el = el;
    if ($('no-image-captions')) {
      return;
    }
    if (!this.imageIsLoaded(el)) {
      el.addEvent('load', this.setup.bind(this));
    } else {
      this.setup();
    }
  },
  
  setup: function() {
    var trigger = this.setupTrigger();
    var caption = this.setupCaption();
    trigger.addEvent('mouseover', function() {
      caption.removeClass('hidden');
      caption.retrieve('background').removeClass('hidden');
      trigger.addClass('hidden');
      trigger.retrieve('background').addClass('hidden');
    });
    caption.addEvent('mouseleave', function() {
      caption.addClass('hidden');
      caption.retrieve('background').addClass('hidden');
      trigger.removeClass('hidden');
      trigger.retrieve('background').removeClass('hidden');
    });
  },
  
  setupTrigger: function() {
    var coordinates = this.el.getCoordinates($('main'));
    var className = 'image-caption';
    className += this.el.hasClass('flickr') ? ' flickr-caption' : '';
    var trigger = new Element('a', {
      href: '#',
      'class': className,
      text: this.el.hasClass('flickr') ? 'FLICKR' : 'i',
      styles: {
        top: coordinates.top + coordinates.height - 16
      }
    }).inject($('main'));
    var size = trigger.getSize();
    trigger.setStyle('left', coordinates.left + coordinates.width - size.x - 5);
    this.addBackground(trigger);
    return trigger;
  },
    
  setupCaption: function() {
    var coordinates = this.el.getCoordinates($('main'));
    var caption = new Element('div', {
      html: this.el.get('longdesc'),
      'class': 'image-caption',
      styles: {
        'max-width': coordinates.width - 26
      }
    }).inject($('main'));
    var size = caption.getSize();
    var top = coordinates.top + coordinates.height - 33;
    if (size.y > 30) {
      top += 17;
    }
    caption.setStyles({
      top: top,
      left: coordinates.left + coordinates.width - size.x - 5
    });
    var background = this.addBackground(caption);
    background.addClass('hidden');
    caption.addClass('hidden');
    caption.setStyle('visibility', 'visible');
    return caption;
  },  
  
  addBackground: function(target) {
    var coordinates = target.getCoordinates($('main'));
    var size = target.getSize();
    var top = coordinates.top;
    var background = new Element('div', {
      'class': 'image-caption-bg',
      styles: {
        top: top - 1,
        left: coordinates.left + coordinates.width - size.x - 1,
        width: size.x,
        height: size.y
      }
    });
    target.store('background', background);
    return background.inject($('main'));
  },
  
  // From sajithmr.com
  imageIsLoaded: function(img) {
    if (!img.complete) {
      return false;
    }
    if (typeof img.naturalWidth != "undefined" &&
        img.naturalWidth === 0) {
      return false;
    }
    return true;
  }
  
});

MoMA.Expander = new Class({
  
  initialize: function(el) {
    var target = $(el.get('rel'));
    if (!target) {
      return;
    }
    target.addClass('hidden');
    target.setStyles({
      position: 'absolute',
      visibility: 'hidden'
    });
    target.removeClass('hidden');
    target.setStyle('height', target.getSize().y);
    target.setStyles({
      position: 'static',
      visibility: 'visible'
    });
    this.slide = new Fx.Slide(target).hide();
    el.addEvent('click', this.toggle.bind(this));
    var collapse = target.getElement('.collapse');
    if (collapse) {
      collapse.addEvent('click', this.toggle.bind(this));
    }
  },
  
  toggle: function() {
    this.slide.toggle();
    return false;
  }
  
});

MoMA.VisitorInformation = new Class({
  
  initialize: function(el) {
    el.selectedIndex = 0;
    el.addEvent('change', function() {
      window.location = el.options[el.selectedIndex].value;
    });
  }
  
});

MoMA.ENewsSignup = new Class({
  
  initialize: function(el) {
    var defaultValue = true;
    if ($('e-news')) {
      $('e-news').addEvent('focus', function() {
        if (defaultValue) {
          $('e-news').value = '';
          defaultValue = false;
        }
        $('e-news').setStyle('color', '#000');
      });
    }
  }
  
});

MoMA.HomeCalendar = new Class({ 
  
  initialize: function(el) {
    this.el = el;
    this.position = 0;
    this.pageSize = el.getElement('li').getSize().x;
    this.maxPosition = this.pageSize * (el.getElements('li').length - 1);
    
    if (el.getElements('li').length < 2) {
      this.el.getElement('.nav').addClass('hidden');
    }
    
    el.getElements('li h3').each(function(title) {
      title.shorten(35);
    });
    
    this.slider = el.getElement('ol');
    this.prevButton = el.getElement('.prev');
    this.nextButton = el.getElement('.next');
    this.slider.set('tween', {
      duration: 500,
      transition: Fx.Transitions.Quart.easeOut
    });
    this.prevButton.addEvent('click', this.prev.bind(this));
    this.nextButton.addEvent('click', this.next.bind(this));
  },
  
  prev: function() {
    if (!this.prevButton.hasClass('disabled')) {
      this.position += this.pageSize;
      this.slider.tween('left', this.position);
      this.nextButton.removeClass('disabled');
      if (this.position >= 0) {
        this.slider.setStyle('left', 0);
        this.prevButton.addClass('disabled');
      }
    }
    return false;
  },
  
  next: function() {
    if (!this.nextButton.hasClass('disabled')) {
      this.position -= this.pageSize;
      this.slider.tween('left', this.position);
      this.prevButton.removeClass('disabled');
      if (this.position <= -this.maxPosition) {
        this.slider.setStyle('left', -this.maxPosition);
        this.nextButton.addClass('disabled');
      }
    }
    return false;
  }
  
});

MoMA.HomeNews = new Class({ 
  
  initialize: function(el) {
    
  }
  
});

MoMA.UserLogin = new Class({ 
  
  initialize: function(el) {
    el.addEvent('click', function() {
      Console.openToRegister();
      return false;
    });
  }
  
});

MoMA.SendToPhone = new Class({ 
  
  initialize: function(el) {
    el.addEvent('click', function() {
      if ($(document.body).hasClass('ss-phone-enabled')) {
        var request = new Request.JSON({
          url: '/social/shiftspace/server/?method=sms.send',
          data: $H({
            msg: el.get('rel'),
            toself: 1
          }).toQueryString(),
          onComplete: function(json) {
            alert('The event details have been sent to your mobile phone.');
          }
        });
        request.send();
      } else if (!browserIsSupported()) {
        showUpgradeMessage();
      } else {
        alert('To send this event to your phone you must first register and validate your phone number.');
        Console.openToRegister();
      }
      return false;
    });
  }
  
});

MoMA.SharePage = new Class({ 
  
  initialize: function(el) {
    this.el = el;
    this.setupContent();
    this.setupLinks();
    this.setupPageItems();
    $('share').addEvent('click', function() {
      $('share').toggleClass('active');
      $('MoMAShareWidget').toggleClass('visible');
      return false;
    });
    $(document.body).addEvent('click', function(e) {
      var e = new Event(e);
      if ($(e.target).getParent('#MoMAShareWidget')) {
        return true;
      }
      $('MoMAShareWidget').removeClass('visible');
      $('share').removeClass('active');
    });
  },
  
  setupContent: function() {
    var title, meta = $$('meta[name=stitle]');
    if (meta.length > 0) {
      title = meta[0].get('content');
    }
    if (!title) {
      title = document.title;
    }
    this.title = title.replace("MoMA | ", "");
    this.url = window.location.href;
  },
  
  setupLinks: function() {
    this.setupTwitter();
    this.setupDelicious();
    this.setupFacebook();
    this.setupGoogle();
  },
  
  setupPageItems: function() {
    if ($$('.ss-bookmark-share').length === 0) {
      return;
    }
    $$('.ss-bookmark-share').each(function(item) {
      item.addEvent('mouseenter', this.showHoverWidget.bind(this, item));
      item.addEvent('mouseleave', this.hideHoverWidget.bind(this));
    }.bind(this));
  },
  
  showHoverWidget: function(item) {
    var widget = this.getHoverWidget();
    if (!widget) {
      return false;
    }
    var pos = this.getHoverPosition(item);
    widget.setStyles({
      left: pos.x,
      top: pos.y,
      display: 'block'
    });
    widget.inject(item);
  },
  
  hideHoverWidget: function(item) {
    var widget = this.getHoverWidget();
    if (widget) {
      widget.setStyle('display', 'none');
    }
  },
  
  getHoverWidget: function() {
    if (!$('share-hover-widget')) {
      var pageWidget = $('top-nav').getElement('.social');
      if (!pageWidget) {
        return false;
      }
      var widget = pageWidget.clone();
      widget.set('id', 'share-hover-widget');
      widget.getElement('.bookmark').addEvent('click', this.bookmarkItem.bind(this));
      widget.getElement('.share').addEvent('click', this.shareItem.bind(this));
      return widget;
    } else {
      return $('share-hover-widget');
    }
  },
  
  getHoverPosition: function(target) {
    var relative = target.getParent('.relative') || target.getParent('#main') || $('page');
    var pos = target.getPosition(relative);
    if (target.hasClass('ss-exhibition-item')) {
      pos.x += 425;
      pos.y += 60;
      this.getHoverWidget().getElement('.share').set('title', 'Share this exhibition');
    } else if (target.hasClass('ss-event-item')) {
      pos.x += 530;
      pos.y += 7;
      this.getHoverWidget().getElement('.share').set('title', 'Share this event');
    }
    return pos;
  },
  
  bookmarkItem: function() {
    dbug.log('Bookmark');
    return false;
  },
  
  shareItem: function() {
    dbug.log('Share');
    return false;
  },
  
  setupTwitter: function() {
    var status = this.template($('MoMAShareTwitter').get('rel'));
    status = this.encode(status);
    $('MoMAShareTwitter').set('href', 'http://twitter.com/home/?status=' + status);
  },
  
  setupDelicious: function() {
    var urlTemplate = "http://delicious.com/save?jump=yes&url={url}&title={title}";
    var url = this.template(urlTemplate, true);
    $('MoMAShareDelicious').set('href', url);
  },
  
  setupFacebook: function() {
    var urlTemplate = "http://www.facebook.com/sharer.php?u={url}&t={title}";
    var url = this.template(urlTemplate, true);
    $('MoMAShareFacebook').set('href', url);
    $('MoMAShareFacebook').addEvent('click', function() {
      window.open(url, 'sharer', 'toolbar=0,status=0,width=626,height=436');
      return false;
    }.bind(this));
  },
  
  setupGoogle: function() {
    var urlTemplate = "http://www.google.com/bookmarks/mark?op=edit&bkmk={url}&title={title}";
    var url = this.template(urlTemplate, true);
    $('MoMAShareGoogle').set('href', url);
  },
  
  encode: function(value) {
    return encodeURIComponent(value);
  },
  
  template: function(template, encode) {
    return template.substitute({
      title: encode ? this.encode(this.title) : this.title,
      url: encode ? this.encode(this.url) : this.url
    });
  }
  
});

MoMA.CalendarDateRange = new Class({ 
  
  initialize: function(el) {
    this.el = el;
    this.date = $('date');
    this.start = $('startdate');
    this.end = $('enddate');
    this.setupValues();
    this.setupClasses();
    this.setupEvents();
    this.setupButtons();
    this.setupPickers();
  },
  
  setupValues: function() {
    if (this.date.value === '' || this.date.value == 'Enter date') {
      this.date.value = 'Enter date';
      this.date.store('defaultValue', 'Enter date');
    }
    if (this.start.value === '' || this.start.value == 'Start date') {
      this.start.value = 'Start date';
      this.start.store('defaultValue', 'Start date');
    }
    if (this.end.value === '' || this.end.value == 'End date') {
      this.end.value = 'End date';
      this.end.store('defaultValue', 'End date');
    }
  },
  
  setupClasses: function() {
    if (this.date.value != 'Enter date') {
      this.date.removeClass('default');
    }
    if (this.start.value != 'Start date') {
      this.start.removeClass('default');
    }
    if (this.end.value != 'End date') {
      this.end.removeClass('default');
    }
  },
  
  setupEvents: function() {
    this.date.addEvent('focus', this.focusInput.bind(this));
    this.start.addEvent('focus', this.focusInput.bind(this));
    this.end.addEvent('focus', this.focusInput.bind(this));
    this.el.addEvent('submit', this.submit.bind(this));
    this.date.addEvent('click', function() { return false; });
    this.start.addEvent('click', function() { return false; });
    this.end.addEvent('click', function() { return false; });
    document.body.addEvent('click', function(e) {
      if (!$(e.target).getParent('.picker')) {
        this.hidePicker();
      }
    }.bind(this));
  },
  
  setupButtons: function() {
    this.el.getElements('.picker-button').each(function(button) {
      button.addEvent('click', function() {
        var pickerId = button.get('rel');
        if ($(pickerId).hasClass('hidden')) {
          this.showPicker(pickerId);
        } else {
          this.hidePicker(pickerId);
        }
        return false;
      }.bind(this));
    }.bind(this));
  },
  
  setupPickers: function() {
    this.el.getElements('.picker').each(function(picker) {
      var id = picker.get('id').match(/(.+)-picker/)[1];
      var coords = $(id).getCoordinates($('page'));
      picker.setStyles({
        left: coords.left - 1,
        top: coords.top + coords.height - 11
      });
      this.setupPicker(picker);
    }.bind(this));
  },
  
  setupPicker: function(picker) {
    var day, month, year;
    var months = ['Blank', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    var id = picker.get('id').match(/(.+)-picker/)[1];
    if (picker.getParent('#search-day')) {
      picker.getElements('td a').each(function(link) {
        var href = link.get('href');
        var urlRegex = /(\d+)\/(\d+)\/(\d+)/;
        if (href.indexOf('?') != -1) {
          day = parseInt(href.match(/day=(\d+)/)[1], 10);
          month = parseInt(href.match(/month=(\d+)/)[1], 10);
          year = parseInt(href.match(/year=(\d+)/)[1], 10);
        } else if (href.match(urlRegex)) {
          var date = href.match(urlRegex);
          year = parseInt(date[1], 10);
          month = parseInt(date[2], 10);
          day = parseInt(date[3], 10);
        }
        if (month < 10) {
          month = '0' + month;
        }
        if (day < 10) {
          day = '0' + day;
        }
        link.set('href', '/visit/calendar/' + year + '/' + month + '/' + day);
      });
    } else {
      picker.getElements('td a').each(function(link) {
        link.addEvent('click', function() {
          var href = link.get('href');
          var urlRegex = /(\d+)\/(\d+)\/(\d+)/;
          if (href.indexOf('?') != -1) {
            day = parseInt(href.match(/day=(\d+)/)[1], 10);
            month = parseInt(href.match(/month=(\d+)/)[1], 10);
            year = parseInt(href.match(/year=(\d+)/)[1], 10);
          } else if (href.match(urlRegex)) {
            var date = href.match(urlRegex);
            year = parseInt(date[1], 10);
            month = parseInt(date[2], 10);
            day = parseInt(date[3], 10);
          }
          $(id).value = months[month] + ' ' + day + ', ' + year;
          $(id).removeClass('default');
          this.hidePicker(id + '-picker');
          return false;
        }.bind(this));
      }.bind(this));
    }
    picker.getElements('.month-nav a').each(function(link) {
      link.addEvent('click', function() {
        var request = new Request({
          url: link.get('href').replace('/calendar/', '/calendar/date_picker/'),
          method: 'get',
          onComplete: function(html) {
            $(id + '-picker').set('html', html);
            this.setupPicker($(id + '-picker'));
          }.bind(this)
        });
        request.send();
        return false;
      }.bind(this));
    }.bind(this));
  },
  
  focusInput: function(e) {
    e = new Event(e);
    var inputName = $(e.target).get('name');
    this.showPicker(inputName + '-picker');
    if ($(e.target).hasClass('default')) {
      $(e.target).removeClass('default');
      $(e.target).value = '';
    }
  },
  
  showPicker: function(id) {
    $(id).removeClass('hidden');
    if (this.openPicker) {
      this.hidePicker(this.openPicker);
    }
    this.openPicker = id;
  },
  
  hidePicker: function(id) {
    if ($type(id) != 'string' && $type(this.openPicker) == 'string') {
      id = this.openPicker;
    }
    if ($(id)) {
      $(id).addClass('hidden');
    }
    this.openPicker = false;
  },
  
  submit: function() {
    if (this.date.value == 'Enter date') {
      this.date.value = '';
    }
    if (this.start.value == 'Start date') {
      this.start.value = '';
    }
    if (this.end.value == 'End date') {
      this.end.value = '';
    }
    if (this.date.value === '' && this.start.value === '' && this.end.value ||
        this.start.value !== '' && this.end.value === '' ||
        this.end.value !== '' && this.start.value === '') {
      this.setupValues();
      this.setupClasses();
      return false;
    }
  }
  
});

MoMA.Widget = new Class({
  
  initialize: function(el, page) {
    this.el = el;
    this.page = page;
    el.store('widget', this);
    var href = this.getHref();
    if (href) {
      this.load(href);
    }
  },
  
  load: function(href) {
    this.request = new Request({
      method: 'get',
      url: href,
      onComplete: this.inject.bind(this)
    }).send();
  },
  
  getHref: function() {
    var link = this.el.getElement('a');
    if (!link) {
      return false;
    } else {
      var href = link.get('href');
      if (link.get('rel')) {
        if (href.indexOf('?') == -1) {
          href += '?' + link.get('rel');
        } else {
          href += '&' + link.get('rel');
        }
      }
      return href;
    }
  },
  
  inject: function(html) {
    this.el.set('html', html);
    this.page.initializeControllers(this.el);
  }
  
});


MoMA.WidgetLink = new Class({ 
  
  initialize: function(el) {
    el.addEvent('click', function(e) {
      var widgetId = el.get('rel');
      if ($(widgetId) && $(widgetId).retrieve('widget')) {
        var href = el.get('href') + '?widget_id=' + widgetId;
        $(widgetId).retrieve('widget').load(href);
        return false;
      }
    });
  }
  
});


MoMA.ExhibitionImages = new Class({
  
  initialize: function(el) {
    el.getElements('a').each(function(link) {
      link.addEvent('click', function() {
        $('placeholder').set('src', link.get('href'));
        $('placeholder').set('alt', link.get('alt'));
        $('desc').set('html', link.get('alt'));
        return false;
      });
    });
  }
  
});

MoMA.PreviousExhibitions = new Class({
  
  initialize: function(el) {
    this.el = el;
    this.dropDown = el.getElement('.drop-down');
    var link = el.getElement('a.previous');
    if (link) {
      link.addEvent('click', function() {
        return false;
      });
    }
    this.setupDropDown();
    el.addEvent('mouseenter', this.showDropDown.bind(this));
    el.addEvent('mouseleave', this.delayedHideDropDown.bind(this));
    this.dropDown.addEvent('mouseenter', this.resetHideDropDown.bind(this));
  },
  
  setupDropDown: function() {
    var pos = this.el.getPosition($('page'));
    var size = this.el.getSize();
    this.dropDown.setStyles({
      left: pos.x,
      top: pos.y + size.y - 10,
      width: size.x
    });
  },
  
  showDropDown: function() {
    this.resetHideDropDown();
    this.el.addClass('hover');
  },
  
  delayedHideDropDown: function() {
    this.resetHideDropDown();
    this.delayed = this.hideDropDown.delay(500, this);
  },
  
  resetHideDropDown: function() {
    if (this.delayed) {
      $clear(this.delayed);
      this.delayed = false;
    }
  },
  
  hideDropDown: function() {
    this.el.removeClass('hover');
    this.delayed = false;
  }
  
});

MoMA.HomeNews = new Class({
  
  initialize: function(el) {
    this.pages = el.getElements('li');
    this.list = el.getElement('ol');
    this.controls = el.getElement('.pages');
    this.holder = el.getElement('.relative');
    this.list.set('tween', {
      duration: 750,
      transition: Fx.Transitions.Quart.easeOut
    });
    if (this.pages.length > 1) {
      for (var i = 0; i < this.pages.length; i++) {
        this.addPageLink(i);
      }
    }
  },
  
  addPageLink: function(num) {
    var className = (num == 0) ? 'selected' : '';
    var link = new Element('a', {
      href: '#',
      rel: num,
      'class': className,
      html: '&bull;',
      events: {
        click: this.select.bind(this)
      }
    });
    link.inject(this.controls);
  },
  
  select: function(e) {
    e = new Event(e);
    var link = $(e.target);
    var num = parseInt(link.get('rel'));
    this.list.tween('left', -642 * num);
    this.controls.getElements('.selected').removeClass('selected');
    link.addClass('selected');
    return false;
  }
  
});

function setupTextSize() {
  var maxSize = 3;
  var minSize = -3;
  var smaller = $$('a.text-smaller');
  var larger = $$('a.text-larger');
  if (smaller.length != 1 || larger.length != 1) {
    return;
  }
  var smaller = smaller[0];
  var larger = larger[0];
  var size = Cookie.read('text_size') || 0;
  
  if (size == maxSize) {
    larger.addClass('disabled');
  } else if (size == minSize) {
    smaller.addClass('disabled');
  }
  
  smaller.addEvent('click', function() {
    if (size != minSize) {
      size--;
      Cookie.write('text_size', size);
      var css = new Asset.css('/stylesheets/text_size' + size + '.css');
      if (size == minSize) {
        smaller.addClass('disabled');
      }
      larger.removeClass('disabled');
    }
    return false;
  });
  
  larger.addEvent('click', function() {
    if (size != maxSize) {
      size++;
      Cookie.write('text_size', size);
      var css = new Asset.css('/stylesheets/text_size' + size + '.css');
      if (size == maxSize) {
        larger.addClass('disabled');
      }
      smaller.removeClass('disabled');
    }
    return false;
  });
}

MoMA.addEvent('onBeforeInitialize', function() {
  if ($$('.JS_IntroMovie').length > 0) {
    MoMA.addEvent('onIntroComplete', browserSupport);
  } else {
    browserSupport();
  }
  massageAddItemColors();
  setupTextSize();
});

function browserSupport() {
  
  // Hide the bottom nav for iPhone/iPod users
  if (Browser.Platform.ipod) {
    $('nav').addClass('hidden');
  }
  
  // Don't show any message if the browser is a "good" one, or if they've
  // already seen it
  if (browserIsSupported() || hasSeenBrowserSupportMessage()) {
    return;
  }
  $('browser-support').removeClass('hidden');
}

function browserIsSupported() {
  return isFirefox() || isSafari() || isIE7() || isOpera();
}

function showUpgradeMessage() {
  $('browser-support').addClass('terse');
  $('browser-support').removeClass('hidden');
}

function isFirefox() {
  return (Browser.Engine.gecko);
}

function isSafari() {
  // Safari 3 = webkit 525
  return (Browser.Engine.webkit);
}

function isIE7() {
  return (Browser.Engine.trident && Browser.Engine.version > 4);
}

function isIE6() {
  return (Browser.Engine.trident && Browser.Engine.version < 5);
}

function isOpera() {
  return (Browser.Engine.presto);
}

function hasSeenBrowserSupportMessage() {
  if (Cookie.read('hasSeenBrowserSupportMessage')) {
    return true;
  }
  Cookie.write('hasSeenBrowserSupportMessage', 'yes', {
    duration: 0.5 / 24
  });
  return false;
}

function massageAddItemColors() {
  // In the collection list view set a class based on the user's color selection
  if ($('list-view-items')) {
    var colors = $$('.options .colors');
    if (colors.length == 0) {
      return;
    }
    var images = colors[0].getElements('img');
    if (images.length < 3) {
      return;
    }
    if (images[1].get('src').contains('grey_btn_on')) {
      $('list-view-items').addClass('ss-medium');
    } else if (images[2].get('src').contains('black_btn_on')) {
      $('list-view-items').addClass('ss-dark');
    }
  }
}

var dbug = {
  enable: $empty,
  log: function() {
    if (typeof console == 'object') {
      for (var i = 0; i < arguments.length; i++) {
        console.log(arguments[i]);
      }
    }
  }
};

// From hunlock.com
Array.prototype.shuffle = function () { 
  for (var rnd, tmp, i = this.length; i; rnd = parseInt(Math.random()*i, 10), tmp=this[--i], this[i]=this[rnd], this[rnd]=tmp) {
  }
};

// **************************************************************************
// Copyright 2007 - 2009 Tavs Dokkedahl
// Contact: http://www.jslab.dk/contact.php
//
// This file is part of the JSLab Standard Library (JSL) Program.
//
// JSL is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// any later version.
//
// JSL is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// ***************************************************************************

// Return new array with duplicate values removed
Array.prototype.unique =
  function() {
    var a = [];
    var l = this.length;
    for(var i=0; i<l; i++) {
      for(var j=i+1; j<l; j++) {
        // If this[i] is found later in the array
        if (this[i] === this[j]) {
          j = ++i;
        }
      }
      a.push(this[i]);
    }
    return a;
  };

  
Element.implement({
  
  shorten: function(height) {
    var text = this.get('html');
    var closingTags = text.match(/<\/[^>]+>/g);
    closingTags = closingTags ? closingTags.join('') : '';
    var length = text.length;
    var revert = this.expose();
    while (this.getSize().y > height) {
      length--;
      this.set('html', text.substr(0, length) + '&hellip;' + closingTags);
    }
    revert();
  },
  
  expose: function(){
		if (this.getStyle('display') != 'none') return $empty;
		var before = {};
		var styles = { visibility: 'hidden', display: 'block', position:'absolute' };
		//use this method instead of getStyles
		$each(styles, function(value, style){
			before[style] = this.style[style]||'';
		}, this);
		//this.getStyles('visibility', 'display', 'position');
		this.setStyles(styles);
		return (function(){ this.setStyles(before); }).bind(this);
	}

});
  
var perspectiveLinks = [
  [
    {title: "Register to save works of art in the collection"},
    {title: "Register to text content to a mobile number"},
    {title: "Register to create and annotate artwork sets"},
    {title: "Register to save your favorite pages"}
  ], [
    {title: "Welcome back!"},
    {title: "Save works of art in the collection"},
    {title: "Text content to yourself or someone else"},
    {title: "Create and annotate artwork sets"},
    {title: "Save your favorite pages"}
  ], [
    {title: "Get information on planning your visit", href: "\/visit\/plan\/", type: "VISIT"},
    {title: "See what exhibitions are on view", href: "\/explore\/exhibitions", type: "EXHIBITIONS"},
    {title: "Preview works of art that are on view", href: "\/collection\/browse_results.php?unparsed_search=3&previousSelectedArtists=&artistFilterInitial=&allDepartments=true&allDecades=true&allArtists=true&cb_ovo=on&cb_imgo=on&template_id=6", type: "COLLECTION"},
    {title: "Find out what films are showing", href: "\/explore\/films", type: "FILMS"},
    {title: "See what's on today at MoMA", href: "\/visit\/calendar", type: "CALENDAR"}
  ], [
    {title: "See what exhibitions are on view", href: "\/explore\/exhibitions", type: "EXHIBITIONS"},
    {title: "Preview works of art that are on view", href: "\/collection\/browse_results.php?unparsed_search=3&previousSelectedArtists=&artistFilterInitial=&allDepartments=true&allDecades=true&allArtists=true&cb_ovo=on&cb_imgo=on&template_id=6", type: "COLLECTION"},
    {title: "Find out what films are showing", href: "\/explore\/films", type: "FILMS"},
    {title: "See what's on today at MoMA", href: "\/visit\/calendar", type: "CALENDAR"},
    {title: "Find a program to attend", href: "\/learn\/programs\/", type: "PROGRAMS"},
    {title: "Explore video, audio, and interactive content", href: "\/explore\/multimedia", type: "MULTIMEDIA"},
    {title: "Visit for free! Become a member", href: "\/support\/membership\/join", type: "MEMBERSHIP"}
  ], [
    {title: "Find out about upcoming members programs", href: "\/learn\/programs\/members", type: "PROGRAMS"},
    {title: "See 30-second videos with members", href: "\/explore\/moma_voices\/", type: "MoMA VOICES"},
    {title: "Find out about upcoming member previews", href: "\/visit\/calendar\/programs\/41", type: "PROGRAMS"},
    {title: "Films are free to members. See what's playing.", href: "\/explore\/films", type: "FILMS"},
    {title: "Save 10% now at MoMAstore.org", href: "http:\/\/www.momastore.org\/", type: "SHOP"}
  ], [
    {title: "Browse works in the film collection", href: "\/collection\/browse_results.php?criteria=O%3ADE%3AI%3A8|G%3AHI%3AE%3A1&page_number=1&template_id=6&sort_order=1", type: "COLLECTION"},
    {title: "Find out what films are showing", href: "\/explore\/films", type: "FILMS"},
    {title: "Film ticketing information", href: "\/visit\/plan\/#filmticketing", type: "VISIT"},
    {title: "Find out about upcoming film exhibitions", href: "\/explore\/films\/upcoming", type: "FILMS"}
  ], [
    {title: "Get information about visiting with a family", href: "\/visit\/plan\/family", type: "VISIT"},
    {title: "Find out about upcoming family programs", href: "\/learn\/programs\/families", type: "PROGRAMS"},
    {title: "Check out our site for children ages 5-8", href: "\/interactives\/destination\/", type: "INTERACTIVES"},
    {title: "Listen to the Modern Kids audio program", href: "\/visit\/plan\/atthemuseum\/momaaudio", type: "AUDIO"}
  ], [
    {title: "Find out about resources at MoMA", href: "\/learn\/resources\/", type: "RESEARCH RESOURCES"},
    {title: "See upcoming adult programs", href: "\/learn\/programs\/public", type: "PROGRAMS"},
    {title: "Find out about our conservation program", href: "\/explore\/collection\/conservation\/", type: "CONSERVATION"},
    {title: "Browse or search the online collection", href: "\/explore\/collection\/", type: "COLLECTION"}
  ], [
    {title: "See our Modern Teachers site", href: "\/modernteachers\/", type: "RESEARCH RESOURCES"},
    {title: "Find out about our K-12 educator programs", href: "\/learn\/programs\/educators", type: "CONSERVATION"},
    {title: "Browse or search the online collection", href: "\/explore\/collection\/", type: "COLLECTION"},
    {title: "Check out our site for children ages 5-8", href: "\/interactives\/destination\/", type: "INTERACTIVES"},
    {title: "Visit our site for teens", href: "http:\/\/redstudio.moma.org\/", type: "LEARN"}
  ], [
    {title: "Visit our site for teens", href: "http:\/\/redstudio.moma.org\/", type: "LEARN"},
    {title: "Find out about resources at MoMA", href: "\/learn\/resources\/", type: "RESEARCH RESOURCES"},
    {title: "Find MoMA online at YouTube, Facebook, and more", href: "\/explore\/communities", type: "ONLINE COMMUNITIES"},
    {title: "Explore video, audio, and interactive content", href: "\/explore\/multimedia", type: "MULTIMEDIA"}
  ]
];



