/**
	Cropping Widget
	@author: Azmisov
	@version: 0.1a

	Returns a DOM node
	- img: the URL of the image to crop OR the fileList file data
	- size: widget size array [maxWidth, maxHeight]
	- optparams: optional parameters
		- prop: proportional crop [width,height] OR [[minWidth,maxWidth],[minHeight,maxHeight]]
		- id: an id to reference the widget

	TODO
	- use CSS clip! its cross-browser
	- don't use maxWidth/maxHeight (for IE7 compat)
	- resizeWidget
	- cropped preview
	- proportional crops
	- handle inversion
	- PHP resizing
	- HTML5 fileAPI?
**/

$('body').extend("cropWidget",function(img, size, optparams){
	var _p = this;
	//Get widget values
	if (!egg.isset(img)){
		return {
			"getImage":function(){
				var obj = _p.refine("* .crop_area"),
					img = obj.filter("* img").active(),
					obj = obj.active();
				if (!obj) return false;
				var prop = img.naturalWidth/img.clientWidth;
				var dims = [parseInt(obj.offsetLeft*prop), parseInt(obj.offsetTop*prop), parseInt(obj.clientWidth*prop), parseInt(obj.clientWidth*prop)];
				if (isNaN(dims[0]*dims[1]*dims[2]*dims[3])) return false;
				var canv = _p.addChild(true,"canvas",{'width':100,'height':100},{'display':'none'}).active(),
					ctx = canv.getContext('2d');
				ctx.mozImageSmoothingEnabled = true;
				ctx.drawImage(img,dims[0],dims[1],dims[2],dims[3],0,0,100,100);
				var img = canv.toDataURL("image/jpeg");
				canv.parentNode.removeChild(canv);
				return img;
			}
		}
	}
	//Otherwise, create a new widget
	optparams = optparams || {};
	//Resize handlers; THIS should refer to the .cont_area
	var resizer = {
		//mousePos = the mouse position inside the widget
		"N": function(e,mousePos){
			if (mousePos[1] < 0) mousePos[1] = 0;
			this.style.top = mousePos[1]+"px";
			$(this).refine("* .crop_ref2").style("top",(-mousePos[1]-1)+"px");
		},
		"S": function(e,mousePos){
			var bottom = this.parentNode.clientHeight-mousePos[1];
			if (bottom < 0) bottom = 0;
			this.style.bottom = bottom+"px";
		},
		"W": function(e,mousePos){
			if (mousePos[0] < 0) mousePos[0] = 0;
			this.style.left = mousePos[0]+"px";
			$(this).refine("* .crop_ref2").style("left",(-mousePos[0]-1)+"px");
		},
		"E": function(e,mousePos){
			var right = this.parentNode.clientWidth-mousePos[0];
			if (right < 0) right = 0;
			this.style.right = right+"px";
		}
	}
	//Proportional resize handlers
	var propResizer = {
		//mousePos = the mouse position inside the widget
		"N": function(e,mousePos){
			var obj = $(this);
			var dim = [obj.getStyle("left"),obj.getStyle("top")];
			if (mousePos[1] < 0) mousePos[1] = 0;
			//Normalize based on W offset
			var offset = mousePos[1]-dim[1];
			if (dim[0]+offset < 0) offset = -dim[0];
			//Set values
			obj.style({"top":(dim[1]+offset)+"px","left":(dim[0]+offset)+"px"});
			obj.refine("* .crop_ref2").style({"top":(-dim[1]-offset-1)+"px","left":(-dim[0]-offset-1)+"px"});
		},
		"S": function(e,mousePos){
			var obj = $(this);
			var dim = [obj.getStyle("right"),obj.getStyle("bottom")];
			if (mousePos[1] < 0) mousePos[1] = 0;
			//Normalize based on E offset
			var offset = mousePos[1]-this.clientHeight-this.offsetTop;
			if (dim[1]-offset < 0) offset = dim[1];
			if (dim[0]-offset < 0) offset = dim[0];
			//Set values
			obj.style({"bottom":(dim[1]-offset)+"px","right":(dim[0]-offset)+"px"});
		},
		"W": function(e,mousePos){
			var obj = $(this);
			var dim = [obj.getStyle("left"),obj.getStyle("top")];
			if (mousePos[0] < 0) mousePos[0] = 0;
			//Normalize based on N offset
			var offset = mousePos[0]-dim[0];
			if (dim[1]+offset < 0) offset = -dim[1];
			//Set values
			obj.style({"top":(dim[1]+offset)+"px","left":(dim[0]+offset)+"px"});
			obj.refine("* .crop_ref2").style({"top":(-dim[1]-offset-1)+"px","left":(-dim[0]-offset-1)+"px"});
		},
		"E": function(e,mousePos){
			var obj = $(this);
			var dim = [obj.getStyle("right"),obj.getStyle("bottom")];
			if (mousePos[0] < 0) mousePos[0] = 0;
			//Normalize based on S offset
			var offset = mousePos[0]-this.clientWidth-this.offsetLeft;
			if (dim[1]-offset < 0) offset = dim[1];
			if (dim[0]-offset < 0) offset = dim[0];
			//Set values
			obj.style({"bottom":(dim[1]-offset)+"px","right":(dim[0]-offset)+"px"});
		},
		"SW": function(e, mousePos){
			var obj = $(this);
			//Normalize mouse coords
			if (mousePos[1] < 0) mousePos[1] = 0;
			else if (mousePos[1] > this.parentNode.clientHeight) mousePos[1] = this.parentNode.clientHeight;
			if (mousePos[0] < 0) mousePos[0] = 0;
			else if (mousePos[0] > this.parentNode.clientWidth) mousePos[0] = this.parentNode.clientWidth;
			//Get which way we will be resizing from (N or E)
			var dir = this.offsetLeft+this.clientWidth-mousePos[0] < mousePos[1]-this.offsetTop ? 1 : 0;
			//Get offsets from the starting position (bigger is negative)
			var offsets = [mousePos[0]-this.offsetLeft, this.offsetTop+this.clientHeight-mousePos[1]];
			//Normalize based on dir
			var oPos = [this.offsetLeft,this.parentNode.clientHeight-this.offsetTop-this.clientHeight];
			if (oPos[dir ? 0 : 1]+offsets[dir] < 0) offsets[dir] = -oPos[dir ? 0 : 1];
			//Set values
			obj.style({"bottom":(oPos[1]+offsets[dir])+"px","left":(oPos[0]+offsets[dir])+"px"});
			obj.refine("* .crop_ref2").style("left",(-oPos[0]-offsets[dir]-1)+"px");
		},
		"NE": function(e, mousePos){
			var obj = $(this);
			//Normalize mouse coords
			if (mousePos[1] < 0) mousePos[1] = 0;
			else if (mousePos[1] > this.parentNode.clientHeight) mousePos[1] = this.parentNode.clientHeight;
			if (mousePos[0] < 0) mousePos[0] = 0;
			else if (mousePos[0] > this.parentNode.clientWidth) mousePos[0] = this.parentNode.clientWidth;
			//Get which way we will be resizing from (N or E)
			var dir = this.offsetTop+this.clientHeight-mousePos[1] > mousePos[0]-this.offsetLeft ? 1 : 0;
			//Get offsets from the starting position (bigger is negative)
			var offsets = [this.clientWidth+this.offsetLeft-mousePos[0], mousePos[1]-this.offsetTop];
			//Normalize based on dir
			var oPos = [this.parentNode.clientWidth-this.offsetLeft-this.clientWidth,this.offsetTop];
			if (oPos[dir ? 0 : 1]+offsets[dir] < 0) offsets[dir] = -oPos[dir ? 0 : 1];
			//Set values
			obj.style({"top":(oPos[1]+offsets[dir])+"px","right":(oPos[0]+offsets[dir])+"px"});
			obj.refine("* .crop_ref2").style("top",(-oPos[1]-offsets[dir]-1)+"px");
		}
	}
	//Resize registration
	function resize(e){
		var contPos = $(this.parentNode.parentNode).objPos(),
			mousePos = [e.pageX-contPos[0],e.pageY-contPos[1]],
			obj = this.parentNode;
		var type = this.className.substring(6);
		if (type.length == 2){
			//Computes distance to opposite handle to decide between the two
			var dir = false;
			if (type == 'NW'){
				dir = mousePos[0]-obj.offsetLeft < mousePos[1]-obj.offsetTop;
				type = type[dir?1:0];
			}
			else if (type == 'SE'){
				dir = obj.clientWidth+obj.offsetLeft-mousePos[0] < obj.clientHeight+obj.offsetTop-mousePos[1];
				type = type[dir?1:0];
			}
		}
		//Run the resize method
		propResizer[type].call(obj, e, mousePos);

		/* Use this for free-hand resizing
		for (var x in resizer){
			if (type.indexOf(x) != -1)
				propResizer[x].call(this.parentNode, e, mousePos);
		}
		* */
	}
	//Drag handlers
	function move(e){
		var loc = $(this.parentNode).objPos(1);
		//+2 to compensate for borders
		loc[0] += e.mObj[0]-e.mDrag[0];
		loc[1] += e.mObj[1]-e.mDrag[1];
		moveIt.call(this.parentNode,loc);
	}
	//Does the actual moving algorithm; THIS should refer to the .cont_area
	function moveIt(loc){
		var obj = $(this);
		var dims = [obj.getStyle('left'),obj.getStyle('top'),obj.getStyle('right'),obj.getStyle('bottom')];
		//Get current values
		var offset = [];
		offset[0] = loc[0]-dims[0];
		offset[1] = loc[1]-dims[1];
		//Normalize values
		if (offset[0] > 0 && dims[2]-offset[0] < 0) offset[0] = dims[2];
		else if (offset[0] < 0 && dims[0]+offset[0] < 0) offset[0] = -dims[0];
		if (offset[1] > 0 && dims[3]-offset[1] < 0) offset[1] = dims[3];
		else if (offset[1] < 0 && dims[1]+offset[1] < 0) offset[1] = -dims[1];
		//Set new position
		obj.style({"left":(dims[0]+offset[0])+"px","top":(dims[1]+offset[1])+"px","right":(dims[2]-offset[0])+"px","bottom":(dims[3]-offset[1])+"px"});
		//Set image position
		$(this).refine("* .crop_ref2").style({"top":(-dims[1]-offset[1]-1)+"px","left":(-dims[0]-offset[0]-1)+"px"});
	}

	//proportional editing, hardcoded at the moment
	var props = true;
	this.text('');
	var cont = this.zen(true,".crop_cont>span#crop-fileload{Loading image 0%}+img.crop_ref+.crop_mask+.crop_area>(.crop_mask2>img.crop_ref2])+.resizeNW+.resizeNE+.resizeSW+.resizeSE"+(!props ? "+.resizeS+.resizeW+.resizeN+.resizeE":""));
	if (egg.isset(optparams['id'])) cont.attr("id",optparams['id']);
	/* LOAD THE IMAGE */
	if (egg.isFile(img)){
		//Supports jpeg,png,bmp,gif
		if (!img.type.match('image/(png|jpeg|bmp|gif)'))
			return alert("Invalid file type");
		var reader = new FileReader();
		reader.onprogress = function(e){
			var p = Math.round((e.loaded / e.total) * 100);
			$("#crop-fileload").text("Loading image "+p+"%");
		}
		reader.onload = function(e){
			$("#crop-fileload").text("Drawing image...");
			img = e.target.result;
			registerEvents();
		}
		reader.readAsDataURL(img);
	}
	else if (egg.isStr(img)){
		//Use the uploaded image
		$("#crop-fileload").text("Drawing image...");
		registerEvents();
	}

	//Adds handlers for the crop widget
	function registerEvents(){
		cont.filter('* img').attr("src",img);
		//Handler event registration
		cont.filter('*>.crop_area>div').setSuper(true).fire(function(){
			$(this).bind("drag",(this.className == "crop_mask2" ? move : resize));
		});
		//Adjust widget size on image load
		cont.filter('* img.crop_ref').setSuper(false).imgFire(function(e){
			//portrait or landscape?
			var type = this.width < this.height;
			//set max image width/height
			cont.filter('* img').setSuper(true).style({"maxWidth":parseInt(size[0])+"px","maxHeight":parseInt(size[1])+"px"});
			//set widget size
			this.style.display = "block";
			cont.style({"width":$(this).getStyle('width')+"px","height":$(this).getStyle('height')+"px"});

			//Allow them to "draw" the crop area when they drag across the mask
			cont.filter("*>.crop_mask").bind({
				"dragstart":function(e){
					this.style.opacity = .6;
					var obj = this.nextSibling;
					obj.style.display = "block";
					moveIt.call(obj,e.mObj);
					obj.style.right = (obj.parentNode.clientWidth-obj.offsetLeft-2)+"px";
					obj.style.bottom = (obj.parentNode.clientHeight-obj.offsetTop-2)+"px";
				},
				"drag":function(e){
					var contPos = $(this.parentNode).objPos(),
						mousePos = [e.pageX-contPos[0],e.pageY-contPos[1]],
						objPos = $(this.nextSibling).objPos(1);
					//Start resizing
					propResizer["S"].call(this.nextSibling, e, mousePos);
					propResizer["E"].call(this.nextSibling, e, mousePos);
				}
			});
		});
	}

	return this;
});

