/**
 * Boxy 0.1.4 - Facebook-style dialog, with frills
 *
 * (c) 2008 Jason Frame
 * Licensed under the MIT License (LICENSE)
 */
 
/*
 * jQuery plugin
 *
 * Options:
 *   message: confirmation message for form submit hook (default: "Please confirm:")
 * 
 * Any other options - e.g. 'clone' - will be passed onto the boxy constructor (or
 * Boxy.load for AJAX operations)
 */
 
var boxyHasScrollers = false;
jQuery.fn.boxy = function (options) {
  options = options || {};
  return this.each(function () {
    var node = this.nodeName.toLowerCase(),
        self = this;
    if (node == 'a') {
      jQuery(this).click(function () {
        var active = Boxy.linkedTo(this),
            href = this.getAttribute('href'),
            localOptions = jQuery.extend({
            actuator: this,
            title: this.title
          }, options);
        if (active) {active.show()} else if (href.indexOf('#') >= 0) {
          var content = jQuery(href.substr(href.indexOf('#'))),
              newContent = content.clone(true);
          content.remove();
          localOptions.unloadOnHide = false;
          new Boxy(newContent, localOptions)
        } else {
          if (!localOptions.cache) localOptions.unloadOnHide = true;
          Boxy.load(this.href, localOptions)
        }
        return false
      })
    } else if (node == 'form') {
      jQuery(this).bind('submit.boxy', function () {
        Boxy.confirm(options.message || 'Please confirm:', function () {jQuery(self).unbind('submit.boxy').submit()});
        return false
      })
    }
  })
};
function Boxy(element, options) {
  var oself = this;
  oself.autoHide = function () {oself.hide(oself.options.afterHide)};
  this.boxy = jQuery(Boxy.WRAPPER);
  jQuery.data(this.boxy[0], 'boxy', this);
  this.visible = false;
  this.options = jQuery.extend({}, Boxy.DEFAULTS, options || {});
  if (this.options.modal) {
    this.options = jQuery.extend(this.options, {
      center: true,
      draggable: false
    })
  }
  if (this.options.actuator) {
    jQuery.data(this.options.actuator, 'active.boxy', this)
  }
  this.setContent(element || "<div></div>");
  this._setupTitleBar();
  this.boxy.css('display', 'none').appendTo(document.body);
  this.toTop();
  if (this.options.fixed) {
    if (jQuery.browser.msie && jQuery.browser.version < 7) {
      this.options.fixed = false
    } else {this.boxy.addClass('fixed')}
  }
  if (this.options.center && Boxy._u(this.options.x, this.options.y)) {this.center()} else {
    this.moveTo(Boxy._u(this.options.x) ? this.options.x : Boxy.DEFAULT_X, Boxy._u(this.options.y) ? this.options.y : Boxy.DEFAULT_Y)
  }
  if (this.options.show) this.show();
  if (this.options.autoClose) {
    setTimeout(this.autoHide, this.options.autoClose)
  }
};
Boxy.EF = function () {};
jQuery.extend(Boxy, {
  //WRAPPER: "<table cellspacing='0' cellpadding='0' border='0' class='boxy-wrapper'>" + "<tr><td class='boxy-top-left'></td><td class='boxy-top'></td><td class='boxy-top-right'></td></tr>" + "<tr><td class='boxy-left'></td><td><div class='boxy-container'><table cellspacing='0' cellpadding='0' border='0'><tr><td class='boxy-inner'></td></tr><tr><td class='boxy-footer'></td></tr></table></div></td><td class='boxy-right'></td></tr>" + "<tr><td class='boxy-bottom-left'></td><td class='boxy-bottom'></td><td class='boxy-bottom-right'></td></tr>" + "</table>",
  WRAPPER: " <table cellspacing='0' cellpadding='0' border='0' class='boxy-wrapper'><tr><td><div class='boxy-container'><table cellspacing='0' cellpadding='0' border='0'><tr><td class='boxy-inner'></td></tr><tr><td class='boxy-footer'></td></tr></table></div></td></tr></table>",

  DEFAULTS: {
    title: null,
    closeable: true,
    draggable: true,
    clone: false,
    actuator: null,
    center: true,
    show: true,
    modal: false,
    fixed: true,
    closeText: 'close',
    unloadOnHide: true,
    clickToFront: false,
    behaviours: Boxy.EF,
    afterDrop: Boxy.EF,
    afterShow: Boxy.EF,
    afterHide: Boxy.EF,
    beforeUnload: Boxy.EF
  },
  DEFAULT_X: 50,
  DEFAULT_Y: 50,
  zIndex: 25000,
  dragConfigured: false,
  resizeConfigured: false,
  dragging: null,
  load: function (url, options) {
    options = options || {};
    var ajax = {
      url: url,
      type: 'GET',
      dataType: 'html',
      cache: true,
      beforeSend: function (html) {
        new Boxy("<div class='loading ajax_load'>&nbsp;</div>", {
          modal: false
        });
		$('.boxy_close').remove();
      },
      success: function (html) {
        html = jQuery(html);
        if (options.filter) html = jQuery(options.filter, html);
        Boxy.get('.loading').hide();
        new Boxy(html, options)
      }
    };
    jQuery.each(['type', 'cache'], function () {
      if (this in options) {
        ajax[this] = options[this];
        delete options[this]
      }
    });
    jQuery.ajax(ajax)
  },
  get: function (ele) {
    var p = jQuery(ele).parents('.boxy-wrapper');
    return p.length ? jQuery.data(p[0], 'boxy') : null
  },
  linkedTo: function (ele) {
    return jQuery.data(ele, 'active.boxy')
  },
  alert: function (message, callback, options) {
    return Boxy.ask(message, ['OK'], callback, options)
  },
  confirm: function (message, after, options) {
    return Boxy.ask(message, ['OK', 'Cancel'], function (response) {
      if (response == 'OK') after()
    }, options)
  },
  ask: function (question, answers, callback, options) {
    options = jQuery.extend({
      modal: true,
      closeable: false
    }, options || {}, {
      show: true,
      unloadOnHide: true
    });
    var body = jQuery('<div></div>').append(jQuery('<div class="question"></div>').html(question));
    var map = {},
        answerStrings = [];
    if (answers instanceof Array) {
      for (var i = 0; i < answers.length; i++) {
        map[answers[i]] = answers[i];
        answerStrings.push(answers[i])
      }
    } else {
      for (var k in answers) {
        map[answers[k]] = k;
        answerStrings.push(answers[k])
      }
    }
    var buttons = jQuery('<form class="answers"></form>');
    buttons.html(jQuery.map(answerStrings, function (v) {
      return "<input type='button' value='" + v + "' />"
    }).join(' '));
    jQuery('input[type=button]', buttons).click(function () {
      var clicked = this;
      Boxy.get(this).hide(function () {
        if (callback) callback(map[clicked.value])
      })
    });
    body.append(buttons);
    new Boxy(body, options)
  },
  isModalVisible: function () {
    return jQuery('.boxy-modal-blackout').length > 0
  },
  _u: function () {
    for (var i = 0; i < arguments.length; i++) if (typeof arguments[i] != 'undefined') return false;
    return true
  },
  _handleResize: function (evt) {
    var d = jQuery(document);
    jQuery('.boxy-modal-blackout').css('display', 'none').css({
      width: d.width(),
      height: d.height()
    }).css('display', 'block')
  },
  _handleDrag: function (evt) {
    var d;
    if (d = Boxy.dragging) {
      d[0].boxy.css({
        left: evt.pageX - d[1],
        top: evt.pageY - d[2]
      })
    }
  },
  _nextZ: function () {
    return Boxy.zIndex++
  },
  _viewport: function () {
    var d = document.documentElement,
        b = document.body,
        w = window;
    return jQuery.extend(jQuery.browser.msie ? {
      left: b.scrollLeft || d.scrollLeft,
      top: b.scrollTop || d.scrollTop
    } : {
      left: w.pageXOffset,
      top: w.pageYOffset
    }, !Boxy._u(w.innerWidth) ? {
      width: w.innerWidth,
      height: w.innerHeight
    } : (!Boxy._u(d) && !Boxy._u(d.clientWidth) && d.clientWidth != 0 ? {
      width: d.clientWidth,
      height: d.clientHeight
    } : {
      width: b.clientWidth,
      height: b.clientHeight
    }))
  }
});
Boxy.prototype = {
  estimateSize: function () {
    this.boxy.css({
      visibility: 'hidden',
      display: 'block'
    });
    var dims = this.getSize();
    this.boxy.css('display', 'none').css('visibility', 'visible');
    return dims
  },
  getSize: function () {
    return [this.boxy.width(), this.boxy.height()]
  },
  getContentSize: function () {
    var c = this.getContent();
    return [c.width(), c.height()]
  },
  getPosition: function () {
    var b = this.boxy[0];
    return [b.offsetLeft, b.offsetTop]
  },
  getCenter: function () {
    var p = this.getPosition();
    var s = this.getSize();
    return [Math.floor(p[0] + s[0] / 2), Math.floor(p[1] + s[1] / 2)]
  },
  getInner: function () {
    return jQuery('.boxy-inner', this.boxy)
  },
  getContent: function () {
    return jQuery('.boxy-content', this.boxy)
  },
  setContent: function (newContent) {
    newContent = jQuery(newContent).css({
      display: 'block'
    });
    if (this.options.clone) newContent = newContent.clone(true);
    this.getContent().remove();
    this.getInner().append(newContent);
    this._setupDefaultBehaviours(newContent);
    this.options.behaviours.call(this, newContent);
    return this
  },
  moveTo: function (x, y) {
    this.moveToX(x).moveToY(y);
    return this
  },
  moveToX: function (x) {
    if (typeof x == 'number') this.boxy.css({
      left: x
    });
    else this.centerX();
    return this
  },
  moveToY: function (y) {
    if (typeof y == 'number') this.boxy.css({
      top: y
    });
    else this.centerY();
    return this
  },
  centerAt: function (x, y) {
    var s = this[this.visible ? 'getSize' : 'estimateSize']();
    if (typeof x == 'number') this.moveToX(x - s[0] / 2);
    if (typeof y == 'number') this.moveToY(y - s[1] / 2);
    return this
  },
  centerAtX: function (x) {
    return this.centerAt(x, null)
  },
  centerAtY: function (y) {
    return this.centerAt(null, y)
  },
  center: function (axis) {
    var v = Boxy._viewport();
    var o = this.options.fixed ? [0, 0] : [v.left, v.top];
    if (!axis || axis == 'x') this.centerAt(o[0] + v.width / 2, null);
    if (!axis || axis == 'y') this.centerAt(null, o[1] + v.height / 2);
    return this
  },
  centerX: function () {
    return this.center('x')
  },
  centerY: function () {
    return this.center('y')
  },
  resize: function (width, height, after) {
    if (!this.visible) return;
    var bounds = this._getBoundsForResize(width, height);
    this.boxy.css({
      left: bounds[0],
      top: bounds[1]
    });
    this.getContent().css({
      width: bounds[2],
      height: bounds[3]
    });
    if (after) after(this);
    return this
  },
  tween: function (width, height, after) {
    if (!this.visible) return;
    var bounds = this._getBoundsForResize(width, height);
    var self = this;
    this.boxy.stop().animate({
      left: bounds[0],
      top: bounds[1]
    });
    this.getContent().stop().animate({
      width: bounds[2],
      height: bounds[3]
    }, function () {
      if (after) after(self)
    });
    return this
  },
  isVisible: function () {
    return this.visible
  },
  show: function () {
    var windowHeight = parseInt($(window).height());
    var offset = parseInt($(window).height()) / 2.8;
    var safeHeight = windowHeight - offset;
    if (this.boxy.height() > safeHeight) {
      boxyHasScrollers = true;
      $('.boxyme').css({
        "height": safeHeight
      });
      this.moveToX(null).moveToY(null)
    };
    if (this.visible) return;
    if (this.options.modal) {
      var self = this;
      if (!Boxy.resizeConfigured) {
        Boxy.resizeConfigured = true;
        jQuery(window).resize(function () {Boxy._handleResize()})
      }
      $('body').css({
        "overflow": "hidden"
      });
      this.modalBlackout = jQuery('<div class="boxy-modal-blackout"></div>').css({
        zIndex: Boxy._nextZ(),
        width: jQuery(document).width(),
        height: jQuery(document).height()
      }).appendTo(document.body);
      this.toTop();
      if (this.options.closeable) {
        jQuery(document.body).bind('keypress.boxy', function (evt) {
          var key = evt.which || evt.keyCode;
          if (key == 27) {
            self.hide();
            jQuery(document.body).unbind('keypress.boxy')
          }
        })
      }
    }
    this.boxy.stop().show();
    this.visible = true;
    this._fire('afterShow');
    return this
  },
  hide: function (after) {
    if (!this.visible) return;
    var self = this;
    if (this.options.modal) {
      jQuery(document.body).unbind('keypress.boxy');
      this.modalBlackout.animate({
        opacity: 0
      }, 10, function () {
        jQuery(this).remove();
        $('body').css({
          "overflow": "auto"
        });
        if ($('#jolly_control').length) {GlobalPageCallback()}
      })
    }
    this.boxy.stop().animate({
      opacity: 0
    }, 10, function () {
      self.boxy.css({
        display: 'none'
      });
      self.visible = false;
      self._fire('afterHide');
      if (after) after(self);
      if (self.options.unloadOnHide) self.unload()
    });
    return this
  },
  toggle: function () {
    this[this.visible ? 'hide' : 'show']();
    return this
  },
  hideAndUnload: function (after) {
    this.options.unloadOnHide = true;
    this.hide(after);
    return this
  },
  unload: function () {
    this._fire('beforeUnload');
    this.boxy.remove();
    if (this.options.actuator) {
      jQuery.data(this.options.actuator, 'active.boxy', false)
    }
  },
  toTop: function () {
    this.boxy.css({
      zIndex: Boxy._nextZ()
    });
    return this
  },
  getTitle: function () {
    return jQuery('> .title-bar h3', this.getInner()).html()
  },
  setTitle: function (t) {
    jQuery('> .title-bar h3', this.getInner()).html(t);
    return this
  },
  _getBoundsForResize: function (width, height) {
    var csize = this.getContentSize();
    var delta = [width - csize[0], height - csize[1]];
    var p = this.getPosition();
    return [Math.max(p[0] - delta[0] / 2, 0), Math.max(p[1] - delta[1] / 2, 0), width, height]
  },
  _setupTitleBar: function () {
    if (this.options.title) {
      var self = this;
      var tb = jQuery("<div class='title-bar'></div>").html("<h3>" + this.options.title + "</h3>");
      if (this.options.closeable) {
        tb.append(jQuery("<span class='boxy_close close' onclick='Boxy.get(this).hide();'></span>").html(this.options.closeText))
      };
      if (this.options.draggable) {
        tb[0].onselectstart = function () {
          return false
        };
        tb[0].unselectable = 'on';
        tb[0].style.MozUserSelect = 'none';
        if (!Boxy.dragConfigured) {
          jQuery(document).mousemove(Boxy._handleDrag);
          Boxy.dragConfigured = true
        }
        tb.mousedown(function (evt) {
          self.toTop();
          Boxy.dragging = [self, evt.pageX - self.boxy[0].offsetLeft, evt.pageY - self.boxy[0].offsetTop];
          jQuery(this).addClass('dragging')
        }).mouseup(function () {
          jQuery(this).removeClass('dragging');
          Boxy.dragging = null;
          self._fire('afterDrop')
        })
      }
      this.getInner().prepend(tb);
      this._setupDefaultBehaviours(tb)
    } else {	
      var cb = jQuery("<span class='boxy_close close' onclick='Boxy.get(this).hide();'></span>");  
	  this.getInner().prepend(cb);
		}
  },
  _setupDefaultBehaviours: function (root) {
    var self = this;
    if (this.options.clickToFront) {
      root.click(function () {self.toTop()})
    }
    jQuery('.close, .boxyClose', root).click(function () {
      self.hide();
      return false
    }).mousedown(function (evt) {evt.stopPropagation()})
  },
  _fire: function (event) {this.options[event].call(this)}
};
