function Floater (elm, activeSqr, referer, locker, mover, awaysInViewport) {
	this.init = function (elm, activeSqr) {
		this.lock = false;
		this.elm = $(elm);
		this.activeSqr = (typeof activeSqr == 'object' && activeSqr != null && activeSqr.constructor == Square) ? activeSqr : null;
		this.referer = $(referer);
		this.locker = $(locker);
		this.mover = $(mover);
		this.awaysInViewport = (awaysInViewport === true) ? true : false;
		this.moveEventElm = ($.browser.msie) ? $(document.body) : $(window);
		this.relPosElm = $();
		
		var parent = this.elm;
		var pos;
		while (parent = parent.parent()) {
			if (parent.get(0) == document) { break; }
      pos = parent.css('position');
      if (pos == 'absolute' || pos == 'relative') {
      	this.relPosElm = parent;
        break;
      }
		}
		var os = this.elm.offset();
		this.baseX = os.left - (this.elm.outerWidth(true) - this.elm.outerWidth());
		this.baseY = os.top - (this.elm.outerHeight(true) - this.elm.outerHeight());
    this.dragX = 0;
    this.dragY = 0;
		
		$(window).bind('scroll.floater', {_this: this}, floater_scroll_handler);
    /*this.locker.bind('click.floater', {_this: this}, locker_click_handler);*/
    /*this.mover.bind('mousedown.floater', {_this: this}, mover_mousedown_handler);*/
		this.scroll();
		delete this.init;
	}
	
	this.scroll = function () {
		if (!this.lock) {
			var np = this.newPos(new Square(0, 0, this.elm.width(), this.elm.height()));
			this.elm.stop().animate({top: np.y1, left: np.x1}, 100);
    }
  }
  
  this.newPos = function (sqr) {
  	//var areaSqr = new Square(this.baseX - (this.elm.outerWidth(true) - this.elm.outerWidth()), this.baseY - (this.elm.outerHeight(true) - this.elm.outerHeight()), documentWidth(), documentHeight());
  	var ml = (this.elm.outerWidth(true) - this.elm.outerWidth());
		var mt = (this.elm.outerHeight(true) - this.elm.outerHeight());
  	var areaSqr = new Square(this.baseX - ml, this.baseY - mt, documentWidth() - ml, documentHeight() - mt);
  	if (this.awaysInViewport) {
  		areaSqr.intersect(vp); 
		}
		if (this.activeSqr != null) {
			areaSqr.intersect(this.activeSqr);
		}
		if (this.referer.length == 1) {
			var w = this.referer.width();
			var h = this.referer.height();
			var o = this.referer.offset();
			areaSqr.intersect(new Square(o.left, o.top, o.left + w, o.top + h));
			delete w; delete h; delete o;
		}
		var vp = viewportPos();
  	sqr.moveTo(vp.x1, vp.y1);
		sqr.moveBy(this.dragX, this.dragY);
		sqr.moveIn(areaSqr);
		if (this.relPosElm.length > 0) {
			var os = this.relPosElm.offset();
			sqr.moveBy(-os.left, -os.top);
		}
		return sqr;
	}
	
	this.drag = function (x, y) {
		var os = this.elm.offset();
		this.dragXor = this.dragX = (os.left - (this.elm.outerWidth(true) - this.elm.outerWidth())) - $(window).scrollLeft();
		this.dragYor = this.dragY = (os.top - (this.elm.outerHeight(true) - this.elm.outerHeight())) - $(window).scrollTop();
    var pos = this.mover.position();
    this.moverX = x - pos.left;
    this.moverY = y - pos.top;
    this.moveEventElm.bind('mousemove.floater', {_this: this}, mover_mousemove_handler);
    this.moveEventElm.bind('mouseup.floater', {_this: this}, mover_mouseup_handler);
    $(window).bind('scroll.floater_move', function(event){event.preventDefault();});
  }
  
  this.move = function (x, y) {
  	var ew = this.elm.width();
  	var eh = this.elm.height();
  	var sqr = new Square(0, 0, ew, eh);
  	var vpd = {width: (viewportWidth() - ew), height: (viewportHeight() - eh)};
  	var ml = (this.elm.outerWidth(true) - this.elm.outerWidth());
		var mt = (this.elm.outerHeight(true) - this.elm.outerHeight());
  	this.dragX = (x - this.moverX) + this.dragXor;
  	this.dragX = (this.dragX > -ml) ? ((this.dragX < vpd.width) ? this.dragX : vpd.width) : -ml;
  	this.dragY = (y - this.moverY) + this.dragYor;
  	this.dragY = (this.dragY > -mt) ? ((this.dragY < vpd.height) ? this.dragY : vpd.height) : -mt;
		var np = this.newPos(sqr);
  	this.elm.stop().animate({top: np.y1, left: np.x1}, 7);
  }
  
	this.drop = function () {
		delete this.moverX; delete this.moverY; delete this.dragXor; delete this.dragYor;
    this.moveEventElm.unbind('mousemove.floater');
    this.moveEventElm.unbind('mouseup.floater');
    $(window).unbind('scroll.floater_move');
  }
	
	function floater_scroll_handler (event) {
		event.data._this.scroll();
	}
	
  function locker_click_handler (event) {
    event.preventDefault();
    if (event.data._this.lock == true) {
      event.data._this.lock = false;
    } else {
      event.data._this.lock = true;
    }
    return false;
  }
  
  function mover_mousedown_handler (event) {
    if (event.which == 1) {
      event.preventDefault();
      event.data._this.drag(event.pageX, event.pageY);
    }
  }
  
  function mover_mousemove_handler (event) {
  	event.preventDefault();
    event.data._this.move(event.pageX, event.pageY);
    return false;
  }
  
  function mover_mouseup_handler (event) {
  	event.preventDefault();
    event.data._this.drop();
  }
	
	this.init(elm, activeSqr);
}
