(function($){

  /*
   * jQuery.fn.positionAt     
   * Assists positioning DOM elements relative to body
   * @param location   - A String of a named location, DOM Element, Dom Event, or [x,y] array of coordinates
   * @param offsetLeft - added to the calculated x position
   * @param offsetTop  - added to the calculated y position
   */
  $.fn.positionAt = function(location,offsetLeft,offsetTop){
    var params, scrollTop, screenWidth, top, left;   
    offsetLeft = offsetLeft || 0;
    offsetTop  = offsetTop  || 0;
    return this.each(function(){
      var self = $(this);
      if (typeof(location) == "string"){
        params = $.fn.positionAt.locations[location].call(self);
      } else if (location instanceof Array) {
        params = {top:location[1]||0+offsetTop,left:location[0]||0+offsetLeft};
      } else { // Event or DOM Element
        scrollTop   = $(window).scrollTop(); 
        screenWidth = $(window).width();
        if (location.currentTarget) {
          left = location.pageX;
          top  = location.pageY;
        } else {
          location = $(location).offset();
          left = location.left;
          top  = location.top;
        }

        // Ensure we don't clip the screen
        
        if (left + self.outerWidth() + (offsetLeft*2) >= screenWidth){
          left = screenWidth - self.width() - offsetLeft;
        }
        if (top + (offsetTop*2) <= scrollTop) {
          top = scrollTop - (offsetTop*2);
        }

        params = {
          top:  top  + offsetTop,
          left: left + offsetLeft
        };
      }
      if (!params.position){ params.position = "absolute"; }
      self.css(params);
    });
  };

  /*
   * Named locations for use with jQuery.fn.positionAt
   */
  $.fn.positionAt.locations = {
    center: function(){
      var top  = ($(window).height() - this.outerHeight()) / 2,
          left = ($(window).width()  - this.outerWidth())  / 2;
      return {
        position: "absolute",
        margin:0, 
        top:  (top  > 0 ? top  : 0), 
        left: (left > 0 ? left : 0)
      };
    }
  };

	function SingleWindow(){
		this._settings = { show:[], hide:[] };

		this.show = function(content,location,opts){
			this._init(opts);
			var el = this._settings.show[this._settings.show.length-1].call(this,content,location,opts);
			this._restore();
			return el;
		};

		this.hide = function(){
			this._settings.hide[this._settings.hide.length-1].call(this);
			this._restore();
		};

		this.setup = function(opts){
			var self = this;
			$(document).ready(function(){ self._init(opts); });
		};

    // Private

	  // Set context back to initial state
		this._restore = function(){
			var self = this;
			$.each(self._settings,function(k,v){
			 	if (self._settings[k] instanceof Array)	 { self._settings[k].length = 1; }
			});
		};

    // Set initial context or append temporary context
		this._init = function(opts){
			var self = this;
			if (opts instanceof Object) {
				if (opts.init) {
				 	opts.init.call(self);
					delete opts.init;
				}
				$.each(opts,function(k,v){
					if (self._settings[k]) { 
						self._settings[k].push(v); 
					} else {
						self._settings[k] = v;
					}
				});
			}
		};
	}

	$.singleWindow = new SingleWindow();

})(jQuery);

