var UI = window.UI||{};

Element.addMethods({
  makeInvisible : function(element){
    return $(element).setStyle({
      'visibility' : 'hidden'
    });
  },
  makeVisible : function(element){
    return $(element).setStyle({
      'visibility' : 'visible'
    });
  }
});


if(!String.prototype.uncache){
  Object.extend(String.prototype, {
    uncache : function(){
      return this+((this.indexOf('?')!=-1) ? '&' : '?')+'uncache='+new Date().getTime();
    }
  });
}

UI.Modal = Class.create({
  initialize : function(options){
    this.options = Object.extend({
      className : 'ui-modal',
      minHeight : 0,
      offset : 50,
      overlay : true,
      parentElement : $$('body').first(),
      position : 'absolute',
      minWidth : 0,
      zIndex: 500
    }, options||{});
    
    this.createModal();
    if(this.options.overlay){
      this.createOverlay();
    }
    
    Event.observe(window, 'resize', this.position.bindAsEventListener(this));
  },
  createModal : function(){
    this.modal = new Element('div', {className: this.options.className}).setStyle({
      'overflow' : 'visible',
      'position' : this.options.position,
      'zIndex' : this.options.zIndex
    }).hide();
    this.content = new Element('div');
    
    this.modal.insert(this.content);
    this.options.parentElement.insert(this.modal);
    
    this.close = new Element('a', {className: 'ui-modal-close', href: '#'}).update('Close');
    this.modal.insert(this.close);
    this.close.observe('click', this.onClose.bindAsEventListener(this));    
  },
  createOverlay : function(){
    this.overlay = new Element('div', {className: this.options.className+'-overlay'}).setStyle({
      'overflow' : 'hidden',
      'position' : 'absolute',
      'backgroundColor' : '#000',
      'opacity' : 0.8,
      'zIndex' : this.options.zIndex-10,
      'width' : '100%',
      'top' : 0,
      'left' : 0
    }).hide();
    this.options.parentElement.insert(this.overlay);
  },
  resize : function(){
    var c = this.content.style;
    c.width = c.height = 'auto';
    var viewport = document.viewport.getDimensions();
    var dimensions = this.content.getDimensions(); 
    
    var width = this.options.width;
    var height = this.options.height;
    
    if(!width||!height){
      if(!width){
        c.width=dimensions.width/2+'px';
      }
      if(!height){
        c.fontSize='200%';      
      }
      if(!width && this.content.scrollWidth==dimensions.width){
        width = dimensions.width;
        c.width = width+'px';
      }
      if(!height && this.content.getHeight()==dimensions.height){
        height = dimensions.height;
        c.height = height+'px';
      }      
      c.fontSize='';
      if(!width){
        width = Math.max(this.options.minWidth, (viewport.width-(this.options.offset*2)));
        c.width = width+'px';
      }
      if(!height){
        height = Math.min((viewport.height-this.options.offset*2), Math.max(this.content.scrollHeight, this.options.minHeight));
      }
              
    }    
  },
  position : function(){
    
    if(this.overlay){            
      var h = Math.max(this.options.parentElement.getHeight(), document.viewport.getHeight());
      this.overlay.setStyle({
        height: h+'px'
      });
    }

    this.modal.setStyle(this.getPosition(this.modal.getDimensions()));
  },
  getPosition : function(dimensions){
    var scroll = document.viewport.getScrollOffsets();  
    var viewport = document.viewport.getDimensions();    
    var top = (this.options.top) ? this.options.top+scroll.top : Math.max(this.options.offset+scroll.top, Math.max(this.options.offset, (scroll.top+(viewport.height/2))-(dimensions.height/2)));    
    var left = (this.options.left) ? this.options.left : Math.max(this.options.offset, (scroll.left+(viewport.width/2))-(dimensions.width/2));    
    return {
      top : top+'px',
      left: left+'px'
    };
  },
  show : function(){
    this.modal.makeInvisible().show();
    this.resize();
    this.position();
    if(this.options.overlay){
      this.showOverlay();
    }
    this.modal.makeVisible();
  },
  showOverlay : function(){
    this.overlay.show();
  },
  hide : function(){
    this.modal.stopObserving();
    this.modal.hide();
    if(this.options.overlay){
      this.hideOverlay();
    }
  },
  hideOverlay : function(){
    this.overlay.hide();
  },
  update : function(html){
    this.modal.stopObserving();
    this.content.update(html);
  },
  onClose : function(e){
    e.stop();
    this.hide();
  },
  destroy : function(){
    
  }
});

UI.AjaxModal = Class.create(UI.Modal, {
  initialize : function($super, selector, options){
    $super(options);
    this.selector = selector;
    document.observe('click', this.onclick.bindAsEventListener(this));
  },
  onclick : function(e){
    var element = e.findElement(this.selector);
    if(element && element.href){
      e.stop();
      this.load(element.href);
    } 
  },
  load : function(url){
    new Ajax.Request(url.uncache(), {
      method : 'get',
      onSuccess : this.onLoad.bind(this)
    });
  },
  onLoad : function(t){
    var overlay = t.request.url
    overlay = overlay.substring(overlay.lastIndexOf('/'),overlay.lastIndexOf('?'));
    this.update(t.responseText);
    pageTracker._trackPageview("/overlay"+overlay);
    this.show.bind(this).defer();
  }
});

UI.LightboxModal = Class.create(UI.Modal, {
  initialize : function($super, selector, options){
    $super(options);
    this.selector = selector;
    document.observe('click', this.onclick.bindAsEventListener(this));
  },
  onclick : function(e){
    var element = e.findElement(this.selector);
    if(element && element.href){
      e.stop();
      this.load(element);
    } 
  },
  load : function(element){
    if(element.rel){
      var slides = $A();
      $$(this.selector+'[rel='+element.rel+']').each(function(slide, i){
        slides.push([slide.href, slide.title||'']); 
        if(slide==element){
          index = i;
        }
      });
      this.slideshow = new UI.Slideshow(this.content, slides, {
        index: index,
        onLoad : this.onLoad.bind(this)
      });  
      this.show();
    }
  },
  onLoad : function(image){
    var dimensions = this.slideshow.element.getDimensions();

    var position = this.getPosition({
      height : dimensions.height,
      width: image.width
    });
   
   new Effect.Parallel([
     new Effect.Morph(this.modal, {
       style : position,
       sync : true
     }),
     new Effect.Morph(this.content, {
       style : {
         height: dimensions.height+'px',
         width: image.width+'px'
       },
       sync : true
     })
    ], {
      queue : 'end',
      beforeStart : function(){
        this.slideshow.div1.hide();
      }.bind(this),
      afterFinish : function(){
        this.slideshow.div1.show();
      }.bind(this)
  });
   
   
   
   
  }
});

UI.Slideshow = Class.create({
  initialize : function(element, slides, options){
    this.slides = slides;
    this.root = $(element);
    this.root.style.overflow = 'hidden';
    
    this.options = Object.extend({
      className : 'ui-slideshow',
      controlsClassName : 'ui-slideshow-controls',
      delay : 5,
      index: 0,
      onLoad : Prototype.emptyFunction,
      onPause : Prototype.emptyFunction,
      onPlay : Prototype.emptyFunction,
      nextClassName : 'ui-slideshow-next',
      nextText : 'Next',
      pauseClassName : 'ui-slideshow-pause',
      pauseText : 'Pause',
      playClassName : 'ui-slideshow-play',
      playText : 'Play',
      previousClassName : 'ui-slideshow-previous',
      previousText : 'Previous',
      statusClassName : 'ui-slideshow-status',
      statusText : 'Image #{index} of #{count}'
    }, options||{});
    
    this.index = this.options.index;
    
    this.build();
    this.show();
  },
  build : function(){
    this.element = new Element('div', {className: this.options.className}).update('<div><div><img /></div><div><img /></div></div><div class="ui-slideshow-controls"><ul class="ui-slideshow-player-controls"><li class="#{playClassName}"><a href="#">#{playText}</a></li><li class="#{pauseClassName}"><a href="#">#{pauseText}</a></li></ul><ul class="ui-slideshow-manual-controls"><li class="#{previousClassName}"><a href="#">#{previousText}</a></li><li class="#{nextClassName}"><a href="#">#{nextText}</a></li></ul><p class="#{statusClassName}"></p></div>'.interpolate(this.options));
    this.element.identify();
    this.wrapper = this.element.down('div').setStyle({position: 'relative'});
    
    this.div1 = this.wrapper.down('div');
    this.div2 = this.div1.next().setStyle({'position' : 'absolute', 'top' : 0, 'left' : 0});    
    
    this.image1 = this.div1.down('img').setStyle({'display' : 'block'});
    this.image2 = this.div2.down('img').setStyle({'display': 'block'});
    
    this.status = this.element.down('.'+this.options.statusClassName);
    this.previousLink = this.element.down('.'+this.options.previousClassName);
    this.nextLink = this.element.down('.'+this.options.nextClassName);
    this.playLink = this.element.down('.'+this.options.playClassName);
    this.pauseLink = this.element.down('.'+this.options.pauseClassName).hide();
    this.controls = this.element.down('.'+this.options.controlsClassName);
    this.root.insert(this.element);
    this.element.observe('click', this.onClick.bindAsEventListener(this));
    
    if(this.options.height && this.options.width){
      this.wrapper.setStyle({
        height: this.options.height+'px',
        width: this.options.width+'px',
        overflow : 'hidden'
      })
    }
    
  },
  show : function(i){
    if(i) this.index = i;
    this.controls.makeInvisible();
    this.nextLink[(this.index+1==this.slides.size()) ? 'hide' : 'show']();
    this.previousLink[(this.index==0) ? 'hide' : 'show']();
    
    var image = new Image();
    image.onload = this.onLoad.bind(this, image);
    image.src = this.slides[this.index][0];
  },
  onLoad : function(image){   
    if(this.image2.src){
      new Effect.Fade(this.div2, {
        queue: 'end'
      })
    }   
    
    this.div1.setStyle({
      opacity: 0
    });
    this.image1.src = image.src;
    this.status.update(this.options.statusText.interpolate({
      index: this.index+1,
      count: this.slides.size()
    }));
    
    this.options.onLoad(image);
    
    new Effect.Appear(this.div1, {
      queue: 'end',
      afterFinish : function(){
        this.image2.src = this.image1.src;
        if(this.playing){
          this._play();
        }
        this.controls.makeVisible();
      }.bind(this)
    });
    
  },
  _onLoad : function(image){
    
    var animations = [];
    
    if(this.image2.src){
      this.div2.show();
      animations.push(new Effect.Fade(this.div2, {
        sync : true
      }));
    }
    
    this.image1.src = image.src;
    this.status.update(this.options.statusText.interpolate({
      index: this.index+1,
      count: this.slides.size()
    }));
    
    
    new Effect.Parallel(animations, {
      afterFinish : function(){
        this.image2.src = this.image1.src;
        if(this.playing){
          this._play();
        }
        this.controls.makeVisible();
      }.bind(this)
    });
    
  },
  onClick : function(e){
    if(e.findElement('.'+this.options.nextClassName)){
      e.stop();   
      this._pause();   
      this.navigate(1);
    }else if(e.findElement('.'+this.options.previousClassName)){
      e.stop();
      this._pause();
      this.navigate(-1);
    }else if(e.findElement('.'+this.options.playClassName)){
      e.stop();
      this._pause();
      this.play();
    }else if(e.findElement('.'+this.options.pauseClassName)){
      e.stop();
      this.pause();
    }
  },
  navigate : function(i){
    this.index += i||0;
    if(this.index == this.slides.size()) this.index = 0;
    if(this.index == -1) this.index = this.slides.size()-1;
    this.show();
  },
  play : function(){
    this._play();
    this.playLink.hide();
    this.pauseLink.show();
    this.options.onPlay();    
  },
  _play : function(){
    this.playing = true;
    this.player = this.navigate.bind(this, 1).delay(this.options.delay);
  },
  pause : function(){
    this._pause();
    this.playLink.show();
    this.pauseLink.hide();
    this.options.onPause();
  },
  _pause : function(){
    window.clearTimeout(this.player);
    this.player = this.playing = false;
  },
  destroy : function(){
    if(this.playing){
      this._pause();
    }
    this.element.stopObserving();
    this.element.remove();
  }
});