/**
 * @author Ryan Johnson <ryan@livepipe.net>
 * @copyright 2007 LivePipe LLC
 * @package Control.Modal
 * @license MIT
 * @url http://livepipe.net/projects/control_modal/
 * @version 1.2.12
 */

if(typeof(Control) == "undefined")
  Control = {};
Control.Modal = Class.create();
Object.extend(Control.Modal,{
  loaded: false,
  responders: $A([]),
  overlay: false,
  container: false,
  current: false,
  ie: false,
  targetRegexp: /#(.+)$/,
  imgRegexp: /\.(jpe?g|gif|png|tiff?)$/,
  overlayStyles: {
    position: 'absolute',
    top: 0,
    left: 0,
    zIndex: 9998
  },
  load: function(){
    if(!Control.Modal.loaded){
      Control.Modal.loaded = true;
      Control.Modal.ie = (navigator.appName == 'Microsoft Internet Explorer');
      Control.Modal.overlay = $(document.createElement('div'));
      Control.Modal.overlay.id = 'modal_overlay';
      Object.extend(Control.Modal.overlay.style,Control.Modal.overlayStyles);
      Control.Modal.overlay.hide();
      Control.Modal.container = $(document.createElement('div'));
      Control.Modal.container.id = 'modal_container';
      Control.Modal.container.hide();
      document.getElementsByTagName('body')[0].appendChild(Control.Modal.overlay);
      document.getElementsByTagName('body')[0].appendChild(Control.Modal.container);
    }
  },
  open: function(contents,options){
    m = new Control.Modal(false,$H({contents:contents}).merge(options));
    m.open();
    return m;
  },
  close: function(){
    if(Control.Modal.current)
      Control.Modal.current.close();
  },
  attachEvents: function(){
    Event.observe(window,'load',Control.Modal.load);
    Event.observe(window,'unload',Event.unloadCache,false);
  },
  center: function(){
    element = this.container;
    if(!element._centered){
      this.container.setStyle({
        position: 'absolute'
      }); 
      this.container._centered = true;
    }
    dimensions = Control.Modal.container.getDimensions();
    Position.prepare();
    offset_left = (Position.deltaX + Math.floor((Control.Modal.getWindowWidth() - dimensions.width) / 2));
    offset_top = (Position.deltaY + Math.floor((Control.Modal.getWindowHeight() - dimensions.height) / 2));
    modal_dimensions = Control.Modal.container.getDimensions();
    Control.Modal.container.setStyle({
      top: ((modal_dimensions.height <= Control.Modal.getWindowHeight()) ? ((offset_top != null && offset_top > 0) ? offset_top : '0') + 'px' : 0),
      left: ((modal_dimensions.width <= Control.Modal.getWindowWidth()) ? ((offset_left != null && offset_left > 0) ? offset_left : '0') + 'px' : 0)
    });
  },
  getWindowWidth: function(){
    return (self.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0);
  },
  getWindowHeight: function(){
    return (self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0);
  },
  getDocumentWidth: function(){
    return Math.max(document.body.scrollWidth,Control.Modal.getWindowWidth());
  },
  getDocumentHeight: function(){
    return Math.max(document.body.scrollHeight,Control.Modal.getWindowHeight());
  },  
  onKeyDown: function(event){
    if(event.keyCode == Event.KEY_ESC)
      Control.Modal.close();
  },
  addResponder: function(responder){
    Control.Modal.responders.push(responder);
  },
  removeResponder: function(responder){
    Control.Modal.responders = Control.Modal.responders.without(responder);
  },
  //from Scriptaculous
  setOpacity: function(element,value){
    element= $(element);  
    if(value == 1){
      Element.setStyle(element,{
        opacity: (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : null
      });
    if(/MSIE/.test(navigator.userAgent))
      Element.setStyle(element,{
        filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')
      });  
    }else{  
      if(value < 0.00001) value = 0;  
      Element.setStyle(element, {opacity: value});
      if(/MSIE/.test(navigator.userAgent))  
        Element.setStyle(element,{
          filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + 'alpha(opacity='+value*100+')'
        });  
    }
  }
});
Object.extend(Control.Modal.prototype,{
  mode: '',
  html: false,
  href: '',
  element: false,
  src: false,
  imageLoaded: false,
  initialize: function(element,options){
    this.element = $(element);
    this.options = $H({
      beforeOpen: Prototype.emptyFunction,
      afterOpen: Prototype.emptyFunction,
      beforeClose: Prototype.emptyFunction,
      afterClose: Prototype.emptyFunction,
      beforeLoad: Prototype.emptyFunction,
      onLoad: Prototype.emptyFunction,
      onFailure: Prototype.emptyFunction,
      onException: Prototype.emptyFunction,
      afterLoad: Prototype.emptyFunction,
      beforeImageLoad: Prototype.emptyFunction,
      afterImageLoad: Prototype.emptyFunction,
      contents: false,
      image: false,
      imageTemplate: new Template('<img src="#{src}" id="#{id}"/>'),
      imageAutoDisplay: true,
      imageCloseOnClick: true,
      hover: false,
      iframe: false,
      iframeTemplate: new Template('<iframe src="#{href}" width="100%" height="100%" frameborder="0" id="#{id}"></iframe>'),
      evalScripts: true, //for Ajax, define here instead of in requestOptions
      requestOptions: {}, //for Ajax.Request
      overlayDisplay: true,
      overlayClassName: '',
      overlayCloseOnClick: true,
      containerClassName: '',
      opacity: 0.3,
      zIndex: 9998,
      width: null,
      height: null,
      offsetLeft: 0, //for use with 'relative'
      offsetTop: 0, //for use with 'relative'
      position: 'absolute' //'absolute' or 'relative'
    });
    if(options)
      for(o in options)
        this.options[o] = options[o];
    target_match = false;
    image_match = false;
    if(this.element){
      target_match = Control.Modal.targetRegexp.exec(this.element.href);
      image_match = Control.Modal.imgRegexp.exec(this.element.href);
    }
    if(this.options.contents){
      this.mode = 'contents';
    }else if(this.options.image || image_match){
      this.mode = 'image';
      this.src = this.element.href;
    }else if(target_match){
      this.mode = 'named';
      x = $(target_match[1]);
      this.html = x.innerHTML;
      /* x.remove(); */
      this.href = target_match[1];
    }else{
      this.mode = (this.options.iframe) ? 'iframe' : 'ajax';
      this.href = this.element.href;
    }
    if(this.element){
      if(this.options.hover){
        this.element.observe('mouseover',this.open.bind(this));
        this.element.observe('mouseout',this.close.bind(this));
      }else{
        this.element.onclick = function(){
          this.open();
          return false;
        }.bindAsEventListener(this);
      }
    }
    targets = Control.Modal.targetRegexp.exec(window.location);
    this.position = function(){
      Control.Modal.overlay.setStyle({
        height: Control.Modal.getDocumentHeight() + 'px',
        width: Control.Modal.getDocumentWidth() + 'px'
      });
      if(this.options.position == 'absolute')
        Control.Modal.center();
      else{
        yx = Position.cumulativeOffset(this.element);
        Control.Modal.container.style.position = 'absolute';
        Control.Modal.container.style.top = (yx[1] + this.options.offsetTop) + 'px';
        Control.Modal.container.style.left = (yx[0] + this.options.offsetLeft) + 'px';
      }
    }.bind(this);
    if(this.mode == 'image'){
      this.afterImageLoad = function(){
        if(this.options.imageAutoDisplay && !window.opera)
          $('modal_image').show();
        this.position();
        this.notifyResponders('afterImageLoad');
      }.bind(this);
    }
    if(this.mode == 'named' && targets && targets[1] && targets[1] == this.href)
      this.open();
  },
  open: function(){
    if(!this.options.hover)
      Event.observe($(document.getElementsByTagName('body')[0]),'keydown',Control.Modal.onKeyDown);
    Control.Modal.current = this;
    if(this.notifyResponders('beforeOpen') === false)
      return;
    if(!this.options.hover){
      Control.Modal.overlay.setStyle({
        zIndex: this.options.zIndex
      });
      Control.Modal.setOpacity(Control.Modal.overlay,this.options.opacity);
    }
    Control.Modal.container.setStyle({
      zIndex: this.options.zIndex + 1,
      width: (this.options.width ? this.options.width + 'px' : ''),
      height: (this.options.height ? this.options.height + 'px' : '')
    });
    if(Control.Modal.ie && !this.options.hover){
      $A(document.getElementsByTagName('select')).each(function(select){
        select.style.visibility = 'hidden';
      });
    }
    Control.Modal.overlay.addClassName(this.options.overlayClassName);
    Control.Modal.container.addClassName(this.options.containerClassName);
    switch(this.mode){
      case 'image':
        this.imageLoaded = false;
        this.notifyResponders('beforeImageLoad');
        this.update(this.options.imageTemplate.evaluate({src: this.src, id: 'modal_image'}));
        this.position();
        if(this.options.imageAutoDisplay && !window.opera)
          $('modal_image').hide();
        if(this.options.imageCloseOnClick)
          $('modal_image').observe('click',Control.Modal.close);
        $('modal_image').observe('load',this.afterImageLoad);
        $('modal_image').observe('readystatechange',this.afterImageLoad);
        break;
      case 'ajax':
        this.notifyResponders('beforeLoad');
        options = $H({
          method: 'get',
          onSuccess: function(request){
            this.notifyResponders('onLoad',request);
            this.update(request.responseText);
            if(this.options.evalScripts)
              request.responseText.evalScripts();
            this.notifyResponders('afterLoad',request);
          }.bind(this),
          onFailure: this.options.onFailure,
          onException: this.options.onException
        });
        if(this.options.requestOptions)
          for(o in this.options.requestOptions)
            options[o] = this.options.requestOptions[o];
        new Ajax.Request(this.href,options);
        break;
      case 'iframe':
        this.update(this.options.iframeTemplate.evaluate({href: this.href, id: 'modal_iframe'}));
        this.position();
        break;
      case 'contents':
        this.update((typeof(this.options.contents) == 'function' ? this.options.contents.bind(this)() : this.options.contents));
        break;
      case 'named':
        this.update(this.html);
        break;
    }
    if(!this.options.hover){
      if(this.options.overlayCloseOnClick && this.options.overlayDisplay)
        Control.Modal.overlay.observe('click',Control.Modal.close);
      if(this.options.overlayDisplay)
        Control.Modal.overlay.show();
    }
    this.options.afterOpen();
  },
  update: function(html){
    Control.Modal.container.update(html);
    this.position();
    Control.Modal.container.show();
    if(this.options.position == 'absolute'){
      Event.stopObserving(window,'resize',this.position,false);
      Event.stopObserving(window,'scroll',this.position,false);
      Event.observe(window,'resize',this.position,false);
      Event.observe(window,'scroll',this.position,false);
    }
  },
  close: function(){
    response = this.notifyResponders('beforeClose');
    if(response == false && response != null)
      return;
    if(this.mode == 'image'){
      if(this.options.imageCloseOnClick)
        $('modal_image').stopObserving('click',Control.Modal.close);
      $('modal_image').stopObserving('load',this.afterImageLoad);
      $('modal_image').stopObserving('readystatechange',this.afterImageLoad);
    }
    if(Control.Modal.ie && !this.options.hover){
      $A(document.getElementsByTagName('select')).each(function(select){
        select.style.visibility = 'visible';
      });     
    }
    if(!this.options.hover)
      Event.stopObserving(window,'keyup',Control.Modal.onKeyDown);
    Control.Modal.current = false;  
    Control.Modal.overlay.removeClassName(this.options.overlayClassName);
    Control.Modal.container.removeClassName(this.options.containerClassName);
    Event.stopObserving(window,'resize',this.position,false);
    Event.stopObserving(window,'scroll',this.position,false);
    if(!this.options.hover){
      if(this.options.overlayCloseOnClick && this.options.overlayDisplay)
        Control.Modal.overlay.stopObserving('click',Control.Modal.close);
      if(this.options.overlayDisplay)
        Control.Modal.overlay.hide();
    }
    Control.Modal.container.update('');
    Control.Modal.container.hide();
    this.notifyResponders('afterClose');
  },
  notifyResponders: function(event_name,argument){
    Control.Modal.responders.each(function(responder){
      if(responder[event_name])
        responder[event_name](argument);
    });
    response = this.options[event_name](argument);
    return response;
  }
});
Control.Modal.attachEvents();
