var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}
var Drag = Class.create();
Drag.prototype = {
  initialize: function(obj, drag, options) {
    var oThis = this;
	this._obj = $(obj);
	this.Drag = $(drag);
	this._x = this._y = 0;
	
	this._fM = function(e){ oThis.Move(window.event || e); }
	this._fK = function(e){ oThis.keyMove(window.event || e); }
	this._fS = function(){ oThis.Stop(); }
	
	this.SetOptions(options);
	
	this.Limit = !!this.options.Limit;
	this.mxLeft = parseInt(this.options.mxLeft);
	this.mxRight = parseInt(this.options.mxRight);
	this.mxTop = parseInt(this.options.mxTop);
	this.mxBottom = parseInt(this.options.mxBottom);
	
	this.onMove = this.options.onMove;
	
	this._obj.style.position = "absolute";
	$$E.addEvent(this.Drag, "mousedown", function(e){ oThis.Start(window.event || e); });
	$$E.addEvent(document, 'keydown', this._fK);
  },
  
  SetOptions: function(options) {
    this.options = {
		Limit:		false,
		mxLeft:		0,
		mxRight:	0,
		mxTop:		0,
		mxBottom:	0,
		onMove:		function(){}
    };
   $$.extend(this.options, options || {});
  },

  Start: function(oEvent) {
	
	this._x = oEvent.clientX - this._obj.offsetLeft;
	this._y = oEvent.clientY - this._obj.offsetTop;
	
	$$E.addEvent(document, "mousemove", this._fM);
	$$E.addEvent(document, "mouseup", this._fS);
	
	if($$B.ie){
		$$E.addEvent(this.Drag, "losecapture", this._fS);
		this.Drag.setCapture();
	}else{
		$$E.addEvent(window, "blur", this._fS);
	}
  },
  keyMove:function(oEvent){
		var oEvent = oEvent || window.event;
		var code = (oEvent.keyCode) ? oEvent.keyCode : (oEvent.which) ? oEvent.which : null;
		if (!code) { return true};
		var step = 1;
		if(oEvent.ctrlKey == true) step = 10;
		switch (code){
			case 37: //left
				if(this._obj.offsetLeft > step - 1 || oEvent.shiftKey){
					if(oEvent.shiftKey){
						if(this._obj.offsetWidth - step >= 32) this._obj.style.width = (this._obj.offsetWidth - step) + 'px';
					}else{
						this._obj.style.left = this._obj.offsetLeft - step + "px";
					}
					this.onMove();
				}
			break;
			case 38: //up
				if(this._obj.offsetTop > step - 1 || oEvent.shiftKey){
					if(oEvent.shiftKey){
						if(this._obj.offsetHeight - step >= 32) this._obj.style.height = (this._obj.offsetHeight - step) + 'px';
					}else{
						this._obj.style.top = this._obj.offsetTop - step + "px";
					}
					this.onMove();
				}		
			break;
			case 39: //right
				if (this._obj.offsetLeft + this._obj.offsetWidth + step <= this._obj.parentNode.offsetWidth ){
					if(oEvent.shiftKey){
						this._obj.style.width = (this._obj.offsetWidth + step) + 'px';
					}else{
						this._obj.style.left = this._obj.offsetLeft + step + "px";
					}
					this.onMove();
				}
			break;
			case 40: //down
				if (this._obj.offsetTop + this._obj.offsetHeight + step <= this._obj.parentNode.offsetHeight){
					if(oEvent.shiftKey){
						this._obj.style.height = (this._obj.offsetHeight + step) + 'px';
					}else{
						this._obj.style.top = this._obj.offsetTop + step + "px";
					}
					this.onMove();
				}		
			break;
		}
  },
  Move: function(oEvent) {
	
	window.getSelection && window.getSelection().removeAllRanges();
	
	var iLeft = oEvent.clientX - this._x, iTop = oEvent.clientY - this._y;
	
	if(this.Limit){
		
		var iRight = iLeft + this._obj.offsetWidth - this.mxRight, iBottom = iTop + this._obj.offsetHeight - this.mxBottom;
		
		if(iRight > 0) iLeft -= iRight;
		if(iBottom > 0) iTop -= iBottom;
		if(this.mxLeft > iLeft) iLeft = this.mxLeft;
		if(this.mxTop > iTop) iTop = this.mxTop;
	}
	
	this._obj.style.left = iLeft + "px";
	this._obj.style.top = iTop + "px";	
	
	this.onMove();
  },
  
  Stop: function() {
	
	$$E.removeEvent(document, "mousemove", this._fM);
	$$E.removeEvent(document, "mouseup", this._fS);
	if($$B.ie){
		$$E.removeEvent(this.Drag, "losecapture", this._fS);
		this.Drag.releaseCapture();
	}else{
		$$E.removeEvent(window, "blur", this._fS);
	}
  }
};


var Resize = Class.create();
Resize.prototype = {
  
  initialize: function(obj, options) {
    var oThis = this;
	
	this._obj = $(obj);
	this._right = this._down = this._left = this._up = 0;
	this._scale = 1;
	this._touch = null;
	
	
	var _style = this._obj.currentStyle || document.defaultView.getComputedStyle(this._obj, null);
	this._xBorder = parseInt(_style.borderLeftWidth) + parseInt(_style.borderRightWidth);
	this._yBorder = parseInt(_style.borderTopWidth) + parseInt(_style.borderBottomWidth);
	
	
	this._fR = function(e){ oThis.Resize(e); }
	this._fS = function(){ oThis.Stop(); }
	
	this.SetOptions(options);
	
	this.Limit = !!this.options.Limit;
	this.mxLeft = parseInt(this.options.mxLeft);
	this.mxRight = parseInt(this.options.mxRight);
	this.mxTop = parseInt(this.options.mxTop);
	this.mxBottom = parseInt(this.options.mxBottom);
	
	this.MinWidth = parseInt(this.options.MinWidth);
	this.MinHeight = parseInt(this.options.MinHeight);
	this.Scale = !!this.options.Scale;
	this.ctrlScale = false;
	this.onResize = this.options.onResize;
	
	this._obj.style.position = "absolute";
  },
  
  SetOptions: function(options) {
    this.options = {
		Limit:		true,
		mxLeft:		0,
		mxRight:	0,
		mxTop:		0,
		mxBottom:	0,
		MinWidth:32,
		MinHeight:32,
		Scale:		true,
		onResize:	function(){}
    };
    $$.extend(this.options, options || {});
  },
  
  Set: function(resize, side) {
	var oThis = this, resize = $(resize), _fun, _cursor;
	if(!resize) return;
	
	switch (side.toLowerCase()) {
	case "up" :
		_fun = function(e){ if(oThis.Scale || oThis.ctrlScale){ oThis.scaleUpRight(e); }else{ oThis.SetUp(e); } };
		_cursor = "n-resize";
		break;
	case "down" :
		_fun = function(e){ if(oThis.Scale || oThis.ctrlScale){ oThis.scaleDownRight(e); }else{ oThis.SetDown(e); } };
		_cursor = "n-resize";
		break;
	case "left" :
		_fun = function(e){ if(oThis.Scale || oThis.ctrlScale){ oThis.scaleLeftUp(e); }else{ oThis.SetLeft(e); } };
		_cursor = "e-resize";
		break;
	case "right" :
		_fun = function(e){ if(oThis.Scale || oThis.ctrlScale){ oThis.scaleRightDown(e); }else{ oThis.SetRight(e); } };
		_cursor = "e-resize";
		break;
	case "left-up" :
		_fun = function(e){ if(oThis.Scale || oThis.ctrlScale){ oThis.scaleLeftUp(e); }else{ oThis.SetLeft(e); oThis.SetUp(e); } };
		_cursor = "nw-resize";
		break;
	case "right-up" :
		_fun = function(e){ if(oThis.Scale || oThis.ctrlScale){ oThis.scaleRightUp(e); }else{ oThis.SetRight(e); oThis.SetUp(e); } };
		_cursor = "ne-resize";
		break;
	case "left-down" :
		_fun = function(e){ if(oThis.Scale || oThis.ctrlScale){ oThis.scaleLeftDown(e); }else{ oThis.SetLeft(e); oThis.SetDown(e); } };
		_cursor = "ne-resize";
		break;
	case "right-down" :
	default :
		_fun = function(e){ if(oThis.Scale || oThis.ctrlScale){ oThis.scaleRightDown(e); }else{ oThis.SetRight(e); oThis.SetDown(e); } };
		_cursor = "nw-resize";
	}
	
	resize.style.cursor = _cursor;
	$$E.addEvent(resize, "mousedown", function(e){ oThis._fun = _fun; oThis._touch = resize; oThis.Start(window.event || e); });
  },
  
  Start: function(oEvent, o) {	
	if($$B.ie){ oEvent.cancelBubble = true; } else { oEvent.stopPropagation(); }
	this.ctrlScale = oEvent.ctrlKey;
	this.style_width = this._obj.offsetWidth;
	this.style_height = this._obj.offsetHeight;
	this.style_left = this._obj.offsetLeft;
	this.style_top = this._obj.offsetTop;
	if(this.Scale || this.ctrlScale == true){ 
		this._scale = this.style_width / this.style_height; 
	}
	
	this._left = oEvent.clientX - this.style_width;
	this._right = oEvent.clientX + this.style_width;
	this._up = oEvent.clientY - this.style_height;
	this._down = oEvent.clientY + this.style_height;
	
	if(this.Limit){
		this._mxRight = this.mxRight - this._obj.offsetLeft;
		this._mxDown = this.mxBottom - this._obj.offsetTop;
		this._mxLeft = this.mxLeft + this.style_width + this._obj.offsetLeft;
		this._mxUp = this.mxTop + this.style_height + this._obj.offsetTop;
	}
	
	$$E.addEvent(document, "mousemove", this._fR);
	$$E.addEvent(document, "mouseup", this._fS);
	
	
	if($$B.ie){
		$$E.addEvent(this._touch, "losecapture", this._fS);
		this._touch.setCapture();
	}else{
		$$E.addEvent(window, "blur", this._fS);
	}
  },  
  
  Resize: function(e) {
	if(!this._touch) return;
	window.getSelection && window.getSelection().removeAllRanges();
	this._fun(window.event || e);
	this._obj.style.width = this.style_width - this._xBorder + "px";
	this._obj.style.height = this.style_height - this._yBorder + "px";
	this._obj.style.top = this.style_top + "px";
	this._obj.style.left = this.style_left + "px";	
	
	this.onResize();
  },
  
  
  SetRight: function(oEvent) {
	this.repairRight(oEvent.clientX - this._left);
  },
 
  SetDown: function(oEvent) {
	this.repairDown(oEvent.clientY - this._up);
  },
  
  SetLeft: function(oEvent) {
	this.repairLeft(this._right - oEvent.clientX);
  },
  
  SetUp: function(oEvent) {
	this.repairUp(this._down - oEvent.clientY);
  },
  
  
  scaleRightDown: function(oEvent) {
	
	this.SetRight(oEvent);
	this.repairDown(parseInt(this.style_width / this._scale));
	this.repairRight(parseInt(this.style_height * this._scale));
  },
  
  scaleLeftDown: function(oEvent) {
	this.SetLeft(oEvent);
	this.repairDown(parseInt(this.style_width / this._scale));
	this.repairLeft(parseInt(this.style_height * this._scale));
  },
  
  scaleRightUp: function(oEvent) {
	this.SetRight(oEvent);
	this.repairUp(parseInt(this.style_width / this._scale));
	this.repairRight(parseInt(this.style_height * this._scale));
  },
  
  scaleLeftUp: function(oEvent) {
	this.SetLeft(oEvent);
	this.repairUp(parseInt(this.style_width / this._scale));
	this.repairLeft(parseInt(this.style_height * this._scale));
  },
  
  
  scaleDownRight: function(oEvent) {
	this.SetDown(oEvent);
	this.repairRight(parseInt(this.style_height * this._scale));
	this.repairDown(parseInt(this.style_width / this._scale));
  },
  
  scaleUpRight: function(oEvent) {
	this.SetUp(oEvent);
	this.repairRight(parseInt(this.style_height * this._scale));
	this.repairUp(parseInt(this.style_width / this._scale));
  },
  
  repairRight: function(iWidth) {
	if (iWidth < this.MinWidth){ iWidth = this.MinWidth; }
	if(this.Limit && iWidth > this._mxRight){ iWidth = this._mxRight; }
	this.style_width = iWidth;
  },
  
  repairDown: function(iHeight) {
	if (iHeight < this.MinHeight){ iHeight = this.MinHeight; }
	if(this.Limit && iHeight > this._mxDown){ iHeight = this._mxDown; }
	this.style_height = iHeight;
  },
 
  repairLeft: function(iWidth) {
	if (iWidth < this.MinWidth){ iWidth = this.MinWidth; }
	else if(this.Limit && iWidth > this._mxLeft){ iWidth = this._mxLeft; }
	this.style_width = iWidth;
	this.style_left = this._obj.offsetLeft + this._obj.offsetWidth - iWidth;
  },
  repairUp: function(iHeight) {
	if(iHeight < this.MinHeight){ iHeight = this.MinHeight; }
	else if(this.Limit && iHeight > this._mxUp){ iHeight = this._mxUp; }
	this.style_height = iHeight;
	this.style_top = this._obj.offsetTop + this._obj.offsetHeight - iHeight;
  },
  Stop: function() {
	$$E.removeEvent(document, "mousemove", this._fR);
	$$E.removeEvent(document, "mouseup", this._fS);
	if($$B.ie){
		$$E.removeEvent(this._touch, "losecapture", this._fS);
		this._touch.releaseCapture();
	}else{
		$$E.removeEvent(window, "blur", this._fS);
	}
	this._touch = null;
  }
};

var ImgCropper = Class.create();
ImgCropper.prototype = {
  initialize: function(container, drag, url, width, height, options) {
	var oThis = this;
	this.Container = $(container);
	this.Container.style.position = "relative";
	this.Container.style.overflow = "hidden";
	this.Drag = $(drag);
	this.Drag.style.cursor = "move";
	this.Drag.style.zIndex = 200;
	if($$B.ie){
		this.Drag.style.overflow = "hidden";
		(function(style){
			style.width = style.height = "100%"; 
			style.backgroundColor = "#fff"; 
			style.filter = "alpha(opacity:0)";
		})(this.Drag.appendChild(document.createElement("div")).style)
	}
	this._pic = this.Container.appendChild(document.createElement("img"));
	this._cropper = this.Container.appendChild(document.createElement("img"));
	this._pic.style.position = this._cropper.style.position = "absolute";
	this._pic.style.top = this._pic.style.left = this._cropper.style.top = this._cropper.style.left = "0";
	this._cropper.style.zIndex = 100;
	this._cropper.onload = function(){ oThis.SetPos(); }
	this.Url = url;
	this.Width = parseInt(width);
	this.Height = parseInt(height);
	this.SetOptions(options);
	this.Opacity = parseInt(this.options.Opacity);
	this.dragTop = parseInt(this.options.dragTop);
	this.dragLeft = parseInt(this.options.dragLeft);
	this.dragWidth = parseInt(this.options.dragWidth);
	this.dragHeight = parseInt(this.options.dragHeight);
	this.View = $(this.options.View) || null;
	this.viewWidth = parseInt(this.options.viewWidth);
	this.viewHeight = parseInt(this.options.viewHeight);
	this.resize = this.options.resize || function(){};
	this._view = null;
	if(this.View){
		this.View.style.position = "relative";
		this.View.style.overflow = "hidden";
		this._view = this.View.appendChild(document.createElement("img"));
		this._view.style.position = "absolute";
	}
	this.Scale = parseInt(this.options.Scale);
	this._drag = new Drag(this.Drag, this.Drag, { Limit: true, onMove: function(){ oThis.SetPos(); } });
	this._resize = this.GetResize();
	this.Init();
  },
  
  SetOptions: function(options) {
    this.options = {
		Opacity:30,
		dragTop:	0,
		dragLeft:	0,
		dragWidth:	140,
		dragHeight:90,
		Right:		"",
		Left:		"",
		Up:			"",
		Down:		"",
		RightDown:	"",
		LeftDown:	"",
		RightUp:	"",
		LeftUp:		"",
		Scale:		true,
		resize:function(){},
		View:	"",
		viewWidth:90,
		viewHeight:140
    };
    $$.extend(this.options, options || {});
  },
  
  Init: function() {
	var oThis = this;
	this.Container.style.width = this.Width + "px";
	this.Container.style.height = this.Height + "px";
	this.Drag.style.top = this.dragTop + "px";
	this.Drag.style.left = this.dragLeft + "px";
	this.Drag.style.width = this.dragWidth + "px";
	this.Drag.style.height = this.dragHeight + "px";
	this._pic.src = this._cropper.src = this.Url;
	this._pic.style.width = this._cropper.style.width = this.Width + "px";
	this._pic.style.height = this._cropper.style.height = this.Height + "px";
	if($$B.ie){
		this._pic.style.filter = "alpha(opacity:" + this.Opacity + ")";
	} else {
		this._pic.style.opacity = this.Opacity / 100;
	}
	if(this.View){ this._view.src = this.Url; }
	this._drag.mxRight = this.Width; 
	this._drag.mxBottom = this.Height;
	if(this._resize){ this._resize.mxRight = this.Width; this._resize.mxBottom = this.Height; this._resize.Scale = this.Scale || this.ctrlScale; }
  },
  
  GetResize: function() {
	var op = this.options;
	if(op.RightDown || op.LeftDown || op.RightUp || op.LeftUp || op.Right || op.Left || op.Up || op.Down ){
		var oThis = this, _resize = new Resize(this.Drag, { Limit: true, onResize: function(){ oThis.SetPos(); } });
		if(op.RightDown){ _resize.Set(op.RightDown, "right-down"); }
		if(op.LeftDown){ _resize.Set(op.LeftDown, "left-down"); }
		if(op.RightUp){ _resize.Set(op.RightUp, "right-up"); }
		if(op.LeftUp){ _resize.Set(op.LeftUp, "left-up"); }
		if(op.Right){ _resize.Set(op.Right, "right"); }
		if(op.Left){ _resize.Set(op.Left, "left"); }
		if(op.Up){ _resize.Set(op.Up, "up"); }
		if(op.Down){ _resize.Set(op.Down, "down"); }
		return _resize;
	} else { return null; }
  },  
  
  SetPos: function() {
	var o = this.Drag;
	this._cropper.style.clip = "rect(" + o.offsetTop + "px " + (o.offsetLeft + o.offsetWidth) + "px " + (o.offsetTop + o.offsetHeight) + "px " + o.offsetLeft + "px)";
	this.resize(o);
	if(this.View) this.PreView();
  },  
  
  PreView: function() {
	var o = this.Drag, h = this.viewWidth, w = h * o.offsetWidth / o.offsetHeight;
	if(w > this.viewHeight){
		w = this.viewHeight; 
		h = w * o.offsetHeight / o.offsetWidth; 
	}
	var scale = h / o.offsetHeight;
	var ph = this.Height * scale;
	var pw = this.Width * scale;
	var pt = o.offsetTop * scale;
	var pl = o.offsetLeft * scale;
	var styleView = this._view.style;
	styleView.width = pw + "px"; 
	styleView.height = ph + 1 + "px";
	styleView.top = - pt + "px "; 
	styleView.left = - pl + "px";
  }
};