function debug(message){
  var m = '';
  for(p in message){
    m += p+' : '+message[p]+'<br />';
  }
  document.getElementById('debug').innerHTML += '<div>'+m+'</div>';
}

var UI = window.UI||{};

UI.Modal = Class.create({
  initialize : function(options){
    this.options = Object.extend({
      'animate' : true,
      'closeClassName' : 'ui-modal-close',
      'contentClassName' : 'ui-modal-content',
      'controlsClassName' : 'ui-modal-controls',
      'height' : 0,
      'minHeight' : 100,
      'minWidth' : 100,
      'modalClassName' : 'ui-modal',
      'offset' : '25px 50px',
      'overlayBackgroundColor' : '#000',
      'overlayClassName' : 'ui-modal-overlay',
      'overlayOpacity' : 0.5,
      'rootSelector' : 'body',
      'titleClassName' : 'ui-modal-title',
      'width' : 0,
      'wrapperClassName' : 'ui-modal-wrapper',
      'zIndex' : 500
    }, options||{});

    this.empty = true;
    this.onClickEvent = this.onClick.bindAsEventListener(this);
    this.onResizeEvent = this.onResize.bindAsEventListener(this);
    this.root = $$(this.options.rootSelector).first();
    this.viewport = document.viewport.getDimensions();
    this.visible = false;
    this.zIndex = this.options.zIndex;
    this.build();
    this.registerEvents();
  },
  build : function(){
    this.wrapper = new Element('div', {className : this.options.wrapperClassName}).setStyle({
      'display' : 'none',
      'left' : 0,
      'position' : 'absolute',
      'top' : 0,
      'width' : '100%',
      'zIndex' : this.zIndex
    });
    this.overlay = new Element('div', {className : this.options.overlayClassName}).setStyle({
      'backgroundColor' : this.options.overlayBackgroundColor,
      'height' : '100%',
      'opacity' : this.options.overlayOpacity,
      'width' : '100%'
    });
    this.modal = new Element('div', {className : this.options.modalClassName}).setStyle({
      'left' : 0,
      'position' : 'absolute',
      'top' : 0
    }).update('<ul class="ui-modal-frames"><li class="ui-modal-top"><div class="ui-modal-liquid"><ul class="ui-modal-left"><li class="ui-modal-corner-wrapper"><div class="ui-modal-corner"></div><div class="ui-modal-corner-spacer"></div></li></ul><ul class="ui-modal-right"><li class="ui-modal-corner-wrapper"><div class="ui-modal-corner"></div><div class="ui-modal-corner-spacer"></div></li></ul></div></li><li class="ui-modal-center"><div class="ui-modal-center-bg"><div class="ui-modal-content-wrapper"><div class="ui-modal-title"></div><div class="ui-modal-content" style="width: 100px; height: 100px;"></div><div class="ui-modal-controls"></div></div></div></li><li class="ui-modal-bottom"><div class="ui-modal-liquid"><ul class="ui-modal-left"><li class="ui-modal-corner-wrapper"><div class="ui-modal-corner"></div><div class="ui-modal-corner-spacer"></div></li></ul><ul class="ui-modal-right"><li class="ui-modal-corner-wrapper"><div class="ui-modal-corner"></div><div class="ui-modal-corner-spacer"></div></li></ul></div></li></ul></div>');

    this.close = new Element('a', {className :  this.options.closeClassName, 'href' : '#'}).setStyle({
      'display' : 'none',
      'position' : 'absolute'
    }).update('Close');

    this.title = this.modal.down('div.ui-modal-title');
    this.content = this.modal.down('div.ui-modal-content');
    this.contentOuter = this.modal.down('div.ui-modal-content-wrapper');
    this.controls = this.modal.down('div.ui-modal-controls');
    this.modal.insert(this.close);

    this.wrapper.insert(this.overlay);
    this.wrapper.insert(this.modal);
    this.root.insert(this.wrapper);
  },
  getLayout : function(dimensions){
    var c, cache = {}, cs = this.content.style, d = {'height':0, 'width':0}, h, layout = [], ms = this.modal.style, o = this.getOffset(), p = {}, s = document.viewport.getScrollOffsets(), v = this.viewport, w;
    var _c = this.controls.offsetHeight;
    var _t = this.title.offsetHeight;

    cache.left = ms.left;
    cache.top = ms.top;
    cache.height = cs.height;
    cache.width = cs.width;
    cache._width = ms.width;
    cache.overflow = cs.overflow;

    ms.left = ms.top = 0;
    ms.visibility = 'hidden';
    cs.height = cs.width = 'auto';
    ms.width = '100px';

    var co = this.contentOuter.getDimensions();

    var c = {
      height: this.content.scrollHeight,
      width:  this.content.scrollWidth+4
    };

    if(Prototype.Browser.IE){
      c.width -= 4;
    }

    if(this.p && this.d){
      layout.push(this.p);
      layout.push(this.d);
    }

    if(dimensions && dimensions.width){
      d.width = dimensions.width;
    }else if(this.options.width){
      d.width = this.options.width;
    }else{
      cs.width = c.width/2+'px';
      if(this.content.scrollWidth == c.width){
        d.width = c.width;
      }else{
        d.width = Math.min(c.width, (v.width-(o.left+o.right)));
      }
    }

    d.width = Math.max(this.options.minWidth-co.width, d.width);
    p.width = Math.max(this.options.minWidth, d.width);
    cs.width = d.width+'px';
    ms.width = p.width+'px';

    if(dimensions && dimensions.height){
      d.height = dimensions.height;
    }else if(this.options.height){
      d.height = this.options.height;
    }else{
      d.height = Math.min(c.height, (v.height-(o.top+o.bottom)));
    }

    d.height = Math.max(this.options.minHeight-co.height-25, d.height);

    cs.height = cache.height;
    cs.width = cache.width;
    ms.width = cache._width;
    ms.visibility = '';

    p.top = (this.options.top) ? this.options.top+s.top : Math.max(o.top+s.top, Math.max(o.top, (s.top+((v.height/2)-((d.height+_c+_t+25)/2)))));


    p.left = (this.options.left) ? this.options.left+s.left : Math.max(o.left, (s.left+(v.width/2))-((d.width)/2));

    this.p = p;
    this.d = d;

    layout.push(p);
    layout.push(d);

    return layout;

  },
  getOffset : function(){
    var css = (this.options.offset+'').split(' ');
    var offset = {
      'top' : css[0],
      'right' : css[1]||css[0],
      'bottom' : css[2]||css[0],
      'left' : css[3]||css[1]||css[0]
    };
    for(property in offset){
      offset[property] = parseInt(offset[property], 10);
    }
    return offset;
  },
  setLayout : function(layout){
    this.modal.setStyle(this.styles(layout[0]));
    this.content.setStyle(this.styles(layout[1]));
  },
  show : function(){
    $$('.ui-hide').invoke('makeInvisible');
    this.viewport = document.viewport.getDimensions();
    this.wrapper.setStyle({'height' : Math.max(this.root.getHeight(), this.viewport.height)+'px'});

    this.contentOuter.setStyle({
      'opacity' : 0
    });
    if(this.options.animate){
      this.wrapper.setStyle({
        'opacity' : 0
      }).show();
      this.setLayout(this.getLayout());
      new Effect.Opacity(this.wrapper, {
        'from' : 0,
        'to' : 1,
        'duration' : 0.25,
        'queue' : 'end'
      });
    }else{
      this.wrapper.show();
    }
    return this;
  },
  hide : function(){
    $$('.ui-hide').invoke('makeVisible');
    if(this.options.animate){
      new Effect.Opacity(this.wrapper, {
        'from' : 1,
        'to' : 0,
        'duration' : 0.25,
        'queue' : 'end',
        'afterFinish' : function(){
          this.wrapper.hide();
          this.content.update('');
          this.empty = true;
          this.visible = false;
          this.p = this.d = null;
        }.bind(this)
      });
    }else{
      this.wrapper.hide();
    }
    return this;
  },
  update : function(content){
    var layout, parallel;
    this.content.style.overflow='hidden';
    if(this.options.animate){
      new Effect.Event({
        'beforeSetup' : function(){
          if(!this.empty){
            new Effect.Opacity(this.contentOuter, {
              'from' : 1,
              'to' : 0,
              'duration' : 0.25,
              'queue' : 'start',
              'afterFinish' : function(){
                if(this.afterUpdate){
                  this.afterUpdate();
                }
              }.bind(this)
            });
          }else{
            this.contentOuter.setStyle({
              'opacity' : 0
            });
            if(this.afterUpdate){
              this.afterUpdate();
            }
          }
        }.bind(this),
        'afterSetup' : function(){
          parallel = new Effect.Parallel([], {
            'afterSetup' :  function(){
              this.content.update(content);
              this.empty = false;
              layout = this.getLayout();
              this.setLayout([layout[0], layout[1]]);
              parallel.effects.push(new Effect.Morph(this.modal, {
                'style' : this.styles(layout[2]),
                'sync' : true
              }));
              parallel.effects.push(new Effect.Morph(this.content, {
                'style' : this.styles(layout[3]),
                'sync' : true
              }));
            }.bind(this),
            'queue' : 'end'
          });
        }.bind(this),
        'afterFinish' : function(){
          this.close.setStyle({
            'opacity' : 0
          }).show();
          new Effect.Parallel([
            new Effect.Opacity(this.contentOuter, {
              'from' : 0,
              'to' : 1,
              'sync' : true
            }),
            new Effect.Opacity(this.close, {
              'from' : 0,
              'to' : 1,
              'sync' : true
            })
          ], {
            'duration' : 0.25,
            'queue' : 'end',
            'afterFinish' : function(){
              this.visible = true;
              this.content.style.overflow = '';
            }.bind(this)
          });
        }.bind(this),
        'queue' : 'start'
      });
      return this;
    }
  },
  onClick : function(e){
    var element = e.element();
    if(this.visible && (!element.descendantOf(this.modal) || element == this.close)){
      e.stop();
      this.hide();
    }
  },
  onResize : function(){
    if(this.visible){
      this.resize();
    }
  },
  resize : function(){
    this.viewport = document.viewport.getDimensions();
    this.wrapper.setStyle({'height' : Math.max(this.root.getHeight(), this.viewport.height)+'px'});
    layout = this.getLayout();
    this.setLayout([layout[2], layout[3]]);
  },
  styles : function(object){
    var obj = {};
    for(property in object){
      obj[property] = object[property]+'px';
    }
    return obj;
  },
  registerEvents : function(){
    Event.observe(window, 'resize', this.onResizeEvent);
    document.observe('click', this.onClickEvent);
  },
  unregisterEvents : function(){
    this.content.stopObserving();
    this.content.descendants().invoke('stopObserving');
  },
  destroy : function(){
    this.unregisterEvents();
  }
});

UI.AjaxModal = Class.create(UI.Modal, {
  initialize : function($super, selector, options){
    this.selector = selector;
    options = Object.extend({
    }, options||{});
    $super(options);
  },
  onClick : function($super, e){
    var element = e.element(), link;
    if(link = e.findElement(this.selector)){
      e.stop();
      this.show().load(link.href);
    }else if(this.visible && (!element.descendantOf(this.modal) || element == this.close)){
      e.stop();
      this.hide();
    }
  },
  load : function(url){
    new Ajax.Request(url.uncache(), {
      method : 'get',
      onSuccess : this.onLoad.bind(this)
    });
  },
  onLoad : function(t){
    this.update(t.responseText);
  }
});

UI.Lightbox = Class.create(UI.Modal, {
  initialize : function($super, selector, options){
    this.selector = selector;
    options = Object.extend({
      'delay' : 5,
      'html' : '<div><img src="#{src}" height="#{height}" width="#{width}" /></div>',
      'onLoad' : Prototype.emptyFunction,
      'onPause' : Prototype.emptyFunction,
      'onPlay' : Prototype.emptyFunction,
      'nextButtonClassName' : 'ui-lightbox-next',
      'nextButtonText' : 'Next',
      'pauseButtonClassName' : 'ui-slideshow-pause',
      'pauseButtonText' : 'Pause',
      'playButtonClassName' : 'ui-slideshow-play',
      'playButtonText' : 'Play',
      'previousButtonClassName' : 'ui-lightbox-previous',
      'previousButtonText' : 'Previous',
      'statusClassName' : 'ui-slideshow-status',
      'statusText' : 'Image #{index} of #{count}'
    }, options||{});
    $super(options);

    this.slides = {};
    $$(this.selector).collect(function(slide){
      this.slides[slide.rel||'__'] = this.slides[slide.rel||'__']||[];
      this.slides[slide.rel||'__'].push(slide);
    }, this);
  },
  build : function($super){
    $super();
    this.controls.update('<ul class="ui-lightbox-player-controls"><li class="#{playButtonClassName}"><a href="#" class="button"><span><span><span>#{playButtonText}</span></span></span></a></li><li class="#{pauseButtonClassName}"><a href="#" class="button"><span><span><span>#{pauseButtonText}</span></span></span></a></li></ul><ul class="ui-lightbox-manual-controls"><li class="#{previousButtonClassName}"><a href="#">#{previousButtonText}</a></li><li class="#{nextButtonClassName}"><a href="#">#{nextButtonText}</a></li></ul><p class="#{statusClassName}">#{statusText}</p>'.interpolate(this.options));
    this.statusText = this.controls.down('.'+this.options.statusClassName);
    this.playLink = this.controls.down('.'+this.options.playButtonClassName);
    this.pauseLink = this.controls.down('.'+this.options.pauseButtonClassName).hide();
    this.nextButton = this.controls.down('.'+this.options.nextButtonClassName);
    this.previousButton = this.controls.down('.'+this.options.previousButtonClassName);
  },
  onClick : function($super, e){
    var element, group;
    if(element = e.findElement(this.selector)){
      e.stop();
      this.group = this.slides[element.rel||'__'];
      this.index = this.group.indexOf(element);
      this.show().load(this.index);
    }else{
      if(element = e.findElement('.'+this.options.nextButtonClassName)){
        e.stop();
        this._pause();
        this.navigate(1);
      }else if(element = e.findElement('.'+this.options.previousButtonClassName)){
        e.stop();
        this._pause();
        this.navigate(-1);
      }else if(e.findElement('.'+this.options.playButtonClassName)){
        e.stop();
        this._pause();
        this.play();
      }else if(e.findElement('.'+this.options.pauseButtonClassName)){
        e.stop();
        this.pause();
      }
      $super(e);
    }
  },
  hide : function($super){
    this._pause();
    $super();
  },
  load : function(i){
    if(this.group.size()==1){
      this.playLink.hide();
      this.nextButton.hide();
      this.previousButton.hide();
      this.statusText.hide();
    }else{
      if(this.playing) {
        this.pauseLink.show();
        this.playLink.hide();
      } else {
        this.pauseLink.hide();
        this.playLink.show();
      }

      this.nextButton.show();
      this.previousButton.show();
      this.statusText.show();
    }

    if(!this.empty){
      new Effect.Opacity(this.contentOuter, {
        'from' : 1,
        'to' : 0,
        'duration' : 0.25,
        'queue' : 'start',
        'afterFinish' : function(){
          this.empty = true;
        }.bind(this)
      });
    }

    if(i) this.index = i;
    var image = new Image();
    image.onload = this.onLoad.bind(this, image);
    image.src = this.group[this.index].href;
  },
  show : function($super){
    this.title.update('TITLE').show();
    this.controls.show();
    return $super();
  },
  resize : function($super){
    this.viewport = document.viewport.getDimensions();
    this.wrapper.setStyle({'height' : Math.max(this.root.getHeight(), this.viewport.height)+'px'});

    var image = this.content.down('img');

    var h = this.modal.getHeight()-this.content.getHeight();
    var o = this.getOffset();
    var m = this.viewport.height-o.top-o.bottom-h;

    if(this.height > m){
      image.width = (this.width/this.height)*m;
      image.height = m;
    }

    this.content.style.overflow='hidden';
    this.content.update(this.options.html.interpolate({
      'title' : this.group[this.index].title||'',
      'src' : image.src,
      'height' : image.height,
      'width' : image.width
    }));

    var layout = this.getLayout();
    this.content.style.overflow='';

    this.modal.setStyle(this.styles(layout[2]));
    this.content.setStyle(this.styles(layout[3]));

  },
  onLoad : function(image){
    //return;

    this.title.update(this.group[this.index].title||'&nbsp;');

    this.height = image.height;
    this.width = image.width;

    var h = this.modal.getHeight()-this.content.getHeight();
    var o = this.getOffset();
    var m = this.viewport.height-o.top-o.bottom-h;
    if(this.height > m){
      image.width = (this.width/this.height)*m;
      image.height = m;
    }

    var html = this.options.html.interpolate({
      'title' : this.group[this.index].title||'',
      'src' : image.src,
      'height' : image.height,
      'width' : image.width
    });
    this.update(html);

    if(this.playing){
      this._play();
    }
    image.onload = null;
    image = null;
  },
  afterUpdate : function(){
    this.statusText.update(this.options.statusText.interpolate({
      index : this.index+1,
      count : this.group.size()
    }));
  },
  navigate : function(i){
    this.index += i||0;
    if(this.index == this.group.size()) this.index = 0;
    if(this.index == -1) this.index = this.group.size()-1;
    this.load();
  },
  play : function(){
    this.playLink.hide();
    this.pauseLink.show();
    this._play();
    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;
  }
});