function Popup(target) {
  var isDragging    = false;
  var mouseOffsetX;
  var mouseOffsetY;
  var width         = 350;
  var title;
  var tabs          = false;
  var boundaryMode  = 'horizontal';
  var screenHeight  = $(window).height();
  var screenWidth   = $(window).width();
  var ref = {
    popup     : '.popup',
    title     : '.p-title',
    tabs      : '.p-tabs ul li',
    tabList   : '.p-tabs ul',
    tabCont   : '.p-tabs',
    content   : '.p-content',
    section   : '.p-section',
    top       : '.p-top',
    close     : '.p-close'
  }
  var onReady       = function() {};
  var onClose       = function() {};
  var onMove        = function() {};
  var onChangeTab   = function() {};
  // load popup template from html file
  $.ajax({
    type: "GET",
    url: "popup.html",
    dataType: "html",
    success: function(html) { init(html); }
  });
  this.setBoundaryMode = function(mode) {
    if($.inArray(mode, ['free', 'viewport', 'horizontal', 'vertical']) == -1) {
      alert('Boundary mode not supported!');
    } else {
      boundaryMode = mode;
    }
  }
  this.setTabs = function(tabsArray) {
    tabs = tabsArray;
  }
  this.setWidth = function(px) {
    if(px < 350) {
      alert('Minimum width supported is 350px!');
      px = 350;
    }
    width = px;
  }
  this.setTitle = function(str) {
    title = str;     
  }
  this.evtReady = function(fn) {
    onReady = fn;
  }
  this.evtClose = function(fn) {
    onClose = fn;
  }
  this.evtChangeTab = function(fn) {
    onChangeTab = fn;
  }
  this.open = function() {
    center();
    $(ref.popup).show();
  }
  this.close = function() {
    $(ref.popup).hide();
  }
  this.loadHTML = function(url) {
    $.ajax({
      type: "GET",
      url: url,
      dataType: "html",
      success: function(html) { 
        setPopupContent(html);
        setup();
        onReady();
      }
    });  
  }
  this.loadPHP = function(url, data) {
    data = data == undefined ? false : data;
    $.ajax({
      type: "POST",
      url: url,
      data: data,
      dataType: "json",
      success: function(json) { 
        buildFromJson(json);
        setup();
        onReady();
      }
    });  
  }
  var init = function(html) {
    // replace target element with popup html
    $(target).replaceWith(html);
    $(ref.popup).hide();
  }
  var setup = function() {
    // set popup title and width
    $(ref.title).text(title);
    $(ref.popup).width(width);
    
    // build tabs if tabs is not false
    if(tabs) { buildTabs(); iniTabs(); }
    
    // bind popup events
    bindPopupEvents();
  }
  var center = function() {
    var width = $(ref.popup).outerWidth();
    var height = $(ref.popup).outerHeight();
    var ox = (screenWidth - width) / 2;
    var oy = $(window).scrollTop() + (screenHeight - height) / 2;
    setPosition(ox, oy);  
  }
  var buildTabs = function() {
    $(ref.tabCont).html("<ul></ul>");
    $(tabs).each(function() {
      $(ref.tabList).append("<li>" + this + "</li>");
    });
    bindTabEvents();  
  }
  var buildFromJson = function(json) {
    var jTitle   = json.title == undefined ? false : json.title;
    var jWidth   = json.width == undefined ? false : json.width;
    var jTabs    = json.tabs == undefined ? false : json.tabs;
    var jContent = json.content == undefined ? false : json.content;
    if(jTitle) { title = jTitle; }
    if(jWidth) { width = jWidth; }
    if(jTabs) { tabs = jTabs; }
    if(jContent) { setPopupContent(jContent); }  
  }
  var bindTabEvents = function() {
    $(ref.tabs).hover(function() {
      $(this).addClass("hover").css({"cursor": "pointer"});
    }, function() {
      $(this).removeClass("hover");
    }).click(function() {
      $(ref.tabs).removeClass("active");
      $(this).addClass("active");
      var tabIndex = $(ref.tabs).index(this);
      $(ref.section).hide();
      $($(ref.section).get(tabIndex)).show();
      onChangeTab();
    });    
  }
  var bindPopupEvents = function() {
    $(ref.top).mouseover(function() {
    $(this).css({"cursor": "move"}); 
    }).mousedown(function(e) {
      mouseOffsetX = e.pageX - $(ref.popup).offset().left;
      mouseOffsetY = e.pageY - $(ref.popup).offset().top;
      isDragging = true;
    }).mouseup(function() {
      isDragging = false;
    });
    $(ref.close).mouseover(function() {
      $(this).css({"cursor": "pointer"});
    }).click(function() {
      $(ref.popup).hide();
      onClose();
    });
    $("body").mousemove(function(e) {
      if(isDragging) {
        drag(e);  
      }
    });  
  }
  var drag = function(e) {
    var x = e.pageX - mouseOffsetX;
    var y = e.pageY - mouseOffsetY;
    var right = e.pageX + ($(ref.popup).outerWidth() - mouseOffsetX);
    var bottom = e.pageY + ($(ref.popup).outerHeight() - mouseOffsetY);
    if(x <= 0) {
      x = 0; 
    }
    if(y <= 0) {
      y = 0;
    }
    switch(boundaryMode) {
      case 'viewport':
        if(right >= screenWidth) {
          x = screenWidth - $(ref.popup).outerWidth();
        }
        if(bottom >= screenHeight) {
          y = screenHeight - $(ref.popup).outerHeight();
        }
      break;
      case 'horizontal':
        if(right >= screenWidth) {
          x = screenWidth - $(ref.popup).outerWidth();
        }      
      break;
      case 'vertical':
        if(bottom >= screenHeight) {
          y = screenHeight - $(ref.popup).outerHeight();
        }
      break;
    }
    setPosition(x, y);  
  }
  var setPosition = function(x, y) {
    $(ref.popup).css({"left": x + "px", "top": y + "px"});  
  }
  var setPopupContent = function(html) {
    $(ref.content).append(html);
  }
  var iniTabs = function() {
    $(ref.section + ":not(:first)").hide();
    $(ref.tabs + ":first").addClass('active');
  }
}