//-----------------------------------------------------------------------------
// @CLASS	  : Popup
// @AUTHOR	: Joe D. Tan
// @REQUIRES: Prototype Library version 1.5 (prototype.js)
// @PURPOSE	: Floating IFRAME popup
//-----------------------------------------------------------------------------
var topPopup = null;
var popupCount = 0;
var Popup = Class.create();
Popup.prototype =
{
	initialize: function(contentID, url, callback)
	{
    this.reset();
    this.contentID = contentID;
    this.url = url;
    this.callback = callback;
    this.isIE = navigator.appVersion.match(/\bMSIE\b/);
    this.padding = { top:18, right:4, bottom:4, left:4 };
  },

  reset: function()
  {
    this.url = null;
    this.contentID = null;
    this.contentHome = null;
    this.content = null;
    this.callback = null;
    this.onClose = null;
    this.element = null;
    this.frame = null;
    this.title = null;
    this.dragging = false;
    this.dragX = 0;
    this.dragY = 0;
    this.waitBox = null;
  },

  getPixels: function(element, style)
  {
    var v = Element.getStyle(element, style);
    if (v == null || typeof(v) == 'undefined') return 0;
    if (v.indexOf('em') > 0) alert('oops - getPixels does not support em to px conversion yet');
    v = parseInt(v,10);
    return (isNaN(v) ? 0 : v);
  },
  
  // The width x height is for the IFRAME inside the popup.  The Popup itself will have
  // additional padding to accommodate the chrome.
  open: function(width,height,startX,startY)
  {
    popupCount++;

    Event.observe(window, 'selectstart', this.startSelect.bind(this), false);

    var w = parseInt(width,10);
    var h = parseInt(height,10);

    var div = document.createElement('div');
    this.element = div;
    div.id = 'popup_' + popupCount;
    div.className = 'popup';
    div.style.cursor = 'move';

    // Hack: IE seems to have a bug where border pixels are factored in
    div.style.width = (w + this.padding.left + this.padding.right) + 'px';
    div.style.height = (h + this.padding.top + this.padding.bottom) + 'px';

    var b = document.createElement('div');
    div.appendChild(b);
    b.className = 'popupClose';
    b.style.position = 'absolute';
    b.style.cursor = 'pointer';
    b.style.top = '1px';
    b.style.right = this.padding.right + 'px';
    b.title = 'Close';
    Event.observe(b,'mouseover',function() { this.className = 'popupClose popupCloseActive' }.bind(b), false);
    Event.observe(b,'mouseout',function() { this.className = 'popupClose'; }.bind(b), false);
    Event.observe(b,'click',function() { this.close(true); }.bind(this), false);

    var n = document.createElement('div');
    this.title = n;
    div.appendChild(n);
    n.className = 'popupTitle';
    n.style.position = 'absolute';
    n.style.top = '1px';
    n.style.left = this.padding.left + 'px';
    n.height = '1em';
    Event.observe(n, 'selectstart', this.startSelect.bind(this), false);
    Event.observe(n, 'mousedown', this.preventDefault.bind(this), false);

    var box = null;
    if (this.contentID) // DIV-based
    {
      box = $(this.contentID);
      this.contentHome = (box ? box.parentNode : null);
    }
    else // IFFRAME-based
    {
      box = document.createElement('iframe');
      box.id = 'popup_content_' + popupCount;
      this.contentHome = null;
    }
    if (box)
    {
      div.appendChild(box);
      box.style.cursor = 'pointer';
      box.style.display = 'block';
      
      // On FF, the padding needs to be offset
      var pt = this.getPixels(box,'paddingTop');
      var pr = this.getPixels(box,'paddingRight');
      var pb = this.getPixels(box,'paddingBottom');
      var pl = this.getPixels(box,'paddingLeft');
      box.style.width  = (w - (this.isIE ? 0 : (pl + pr))) + 'px';
      box.style.height = (h - (this.isIE ? 0 : (pt + pb))) + 'px';
      
      if (box.nodeName == 'IFRAME')
      {
        this.frame = box;
        box.frameBorder = 0; // For IE

        box.style.position = 'absolute'; // Only for IFRAMEs
        box.style.margin = '0px 0px';
        box.style.top = this.padding.top + 'px';
        box.style.left = this.padding.left + 'px';

        // The IFRAME may take a while to load, who knows?
        this.showWaitBox('Loading...','load',1);
        box.src = this.url;
      }
      else
      {
        box.style.margin = this.padding.top+ 'px auto ' + this.padding.bottom + 'px auto';
        if (this.isIE) div.style.paddingTop = this.padding.top + 'px';
      }
    }
    this.content = box;
    document.body.appendChild(div);
    
    // Start off in the middle of the page, unless a startX and startY are given
    var startPos = ((typeof(startX) == 'undefined' || typeof(startY) == 'undefined') ? false : true);
    if (!startPos)
      div.style.margin = 'auto auto';

    Position.absolutize(div);
    if (startPos)
    {
      div.style.top = startY;
      div.style.left = startX;
    }
    else
    {
      // Move the dialog to the middle of the screen
      div.style.top = startY = '100px';
    }

    this.moveToTop();

    Event.observe(div, 'mousedown', function(e) {
      this.dragStart(e);
    }.bind(this), false);

  },

  close: function(cancelled)
  {
    this.closeWaitBox();
    var n = this.element;
    if (n && this.waitBox == null)
    {      
      n.style.display = 'none';
      if (this.contentHome && this.contentID)
      {
        var c = $(this.contentID);
        if (c)
        {
          this.contentHome.appendChild(c);
          c.style.display = 'none'; // TODO: Revert to original display style
        }
      }

      n.parentNode.removeChild(n);
    }
    if (this.onClose)
    {
      var f = this.onClose;
      this.onClose = null;
      this.element = null;
      f(this, cancelled);
    }
    if (this.callback) this.callback(this, cancelled);
    this.reset();
  },

  move: function(target, anchor, offsetX, offsetY)
  {
    // Anchor to bottom of the target, with the given X,Y offsets
    if (this.element && target) Element.move(this.element, target, anchor, true, offsetX, offsetY);
    
  },
  
  showWaitBox: function(msg, closeEvent, delaySeconds)
  {
    if (this.waitBox || this.content == null) return;
    this.waitBox = new WaitBox();
    this.waitBox.delaySeconds = (delaySeconds || 0);
    this.waitBox.closeEvent = (closeEvent || null);
    this.waitBox.cover(this.content, msg);
  },
  
  closeWaitBox: function()
  {
    if (this.waitBox)
    {
      this.waitBox.close();
      this.waitBox = null;
    }
  },
  
  setTitle: function(text)
  {
    if (this.title) this.title.innerHTML = text;
  },
  
  moveToTop: function()
  {
    var z = 0;
    if (topPopup)
    {
      topPopup.style.zIndex = popupCount;
      if (this.element) this.element.style.zIndex = (popupCount + 1);
    }
    topPopup = this.element;
  },

  isControl: function(e)
  {
    var n = (Event.element(e) ? Event.element(e).nodeName.toLowerCase() : null);
    return (n == 'input' || n == 'button' || n == 'textarea' || n == 'select');
  },
  
  dragStart: function(e)
  {
    if (this.dragging || this.isControl(e))
      return;

    this.dragging = true;
    var posX;
    var posY;
    if (this.isIE)
    {
      posY = window.event.clientY + document.body.scrollTop;
      posX = window.event.clientX + document.body.scrollLeft;
    }
    else
    {
      posY = e.clientY + window.scrollY;
      posX = e.clientX + window.scrollX;
    }

    this.moveToTop();

    var st = this.element.style;
    this.dragX = posX - parseInt(st.left);
    this.dragY = posY - parseInt(st.top);

    this.dragAddEvents(true);
  },

  dragAddEvent: function(add, args)
  {
      (add ? Event.observe.apply(Event, args) : Event.stopObserving.apply(Event, args));
  },
  
  dragAddEvents: function(add)
  {
    var target = (this.isIE ? document.body : window);
    this.dragAddEvent(add, [ target, 'mousemove', this.dragMove.bind(this), true ]);
    this.dragAddEvent(add, [ target, 'mouseup', this.dragEnd.bind(this), true ]);
    if (this.frame)
    {
      target = this.frame.contentWindow;
      if (target)
      {
        if (this.isIE) target = target.document.body;
        this.dragAddEvent(add, [ target, 'mousemove', this.dragMoveFrame.bind(this), false ]);
        this.dragAddEvent(add, [ target, 'mouseup', this.dragEnd.bind(this), false ]);
      }
    }
  },
  
  dragMoveInternal: function(e, posX, posY)
  {
    // Interesting note: Normally, IE's SELECT lists don't honor zIndex, so they
    // will "float" over any floating DIVs.  Except when the DIV contains an IFRAME!
    if (!(this && this.dragging && this.element))
      return false;

    var st = this.element.style;
    st.left = (posX - this.dragX) + "px";
    st.top  = (posY - this.dragY) + "px";
    return true;
  },
  
  dragMove: function(e)
  {
    this.dragMoveInternal(e, Event.pointerX(e), Event.pointerY(e));
  },
  
  dragMoveFrame: function(e)
  {
    if (this.dragging && this.element)
    {
      // Recalibrate e.pageX, pageY by adding the DIV offset - because mousemouse
      // events in the iframe do not propagate above to the containing window, we
      // need to hand-calculate the "real" x and y position.
      var offsets = Position.positionedOffset(this.element);
      var x = offsets[0] + Event.pointerX(e);
      var y = offsets[1] + Event.pointerY(e);
      this.dragMoveInternal(e,x,y);
    }
  },

  dragEnd: function(e)
  {
    if (!this || !this.element) return false;
    this.dragging = false;
    this.dragAddEvents(false);
  },
  
  startSelect: function(e)
  {
    if (this.dragging)
    {
      Event.stop(e);
      return false;
    }
  },
  
  preventDefault: function(e)
  {
    if (e.preventDefault) e.preventDefault();
    else e.returnValue = false; 
    return false;
  }
};

// Helper functions

function openPopup(divID, callback, width, height, startX, startY)
{
  var p = new Popup(divID, null, callback);
  p.open(width, height, startX, startY);
  return p;
}

function openPopupUrl(url, callback, width, height, startX, startY)
{
  var p = new Popup(null, url, callback);
  p.open(width, height, startX, startY);
  return p;
}


