﻿
BV.appendTextDiv = function(target, text) {
	var div = document.createElement("div");
	div.innerHTML = text;
	target.appendChild(div);
	return div;
}
BV.clearDiv = function(node) {
	while (node.hasChildNodes()) {
		node.removeChild(node.lastChild);
	}
}
//popup will be inside target div
BV.showPopup = function(params, target) {
	var div = document.createElement("div");
	div.id = "intropopup";
	BV.css(div, {
		width: "100%",
		height: "100%",
		position: "absolute",
		//cursor: "default",
		left: 0,
		top: 0
	});
	var background = document.createElement("div");
	BV.css(background, {
		width: "100%",
		height: "100%",
		position: "absolute",
		cursor: "default",
		left: 0,
		top: 0
	});
	div.appendChild(background);
	div.appendChild(params.div);
	params.target.appendChild(div);
	background.onclick = closeFunc;
	/*div.onclick = function() {
		closeFunc();
	}*/
	function closeFunc() {
		params.onClose();
		params.target.removeChild(div);
	};
	params.registerCloseFunc(function()
	{
		closeFunc();
	});
};

BV.popup = function(params) {
	var target = params.target;
	var callback = params.callback;
	var buttons = params.buttons;
	var type = params.type;
	var div = document.createElement("div");
	div.id = "popup";
	div.style.cursor = "default";
	
	BV.css(div, {
		width: "100%",
		height: "100%",
		position: "absolute",
		left: 0,
		top: 0
	});
	var cell = document.createElement("div");
	cell.id = "cell";
	div.appendChild(cell);
	var content = document.createElement("div");
	cell.appendChild(content);
	target.appendChild(div);
	var message = document.createElement("div");
	content.appendChild(message);
	if(params.div) {
		content.appendChild(params.div);
		params.div.style.marginBottom = "20px";
	}
	message.innerHTML = params.message;
	message.style.marginBottom = "10px";
	var buttonWrapper = document.createElement("div");
	buttonWrapper.style.height = "30px";
	var addbutton = function(label) {
		var button = document.createElement("button");
		button.style.cssFloat = "right";
		button.style.minWidth = "80px";
		button.innerHTML = label;
		buttonWrapper.appendChild(button);
		button.onclick = function() {
			target.removeChild(div);
			callback(label);			
		}
	};
	for(var i = params.buttons.length-1; i >= 0; i--) {
		addbutton(params.buttons[i]);
	}
	content.appendChild(buttonWrapper);
	
	BV.css(content, {
		padding: "20px",
		backgroundColor: "#fff",
		width: "300px",
		marginLeft: "auto",
		marginRight: "auto",
		boxShadow: "0px 5px 80px #505050"//"0px 0px 20px rgba(0,0,0,0.5)"
	});
	if(type == "error") {
	content.className = "poperror";
	content.style.paddingLeft = "104px";
	}
	if(type == "ok") {
	content.className = "popok";
	content.style.paddingLeft = "104px";
	}
	if(type == "warning") {
	content.className = "popwarning";
	content.style.paddingLeft = "104px";
	}
	if(type == "trash") {
	content.className = "poptrash";
	content.style.paddingLeft = "104px";
	}
	if(!type) {
	content.className = "popdefault";
	}
	/*content.onclick = function() {
		target.removeChild(div);
	}*/
	
}

//need to revise
BV.attachMouseListener = function(p_el, p_callback, p_return) {
	if(!p_el || !p_callback)
		return false;
	var returnval = false;
	if(p_return === true) {
		returnval = true;
	}
	var el = p_el;
	var callback = p_callback;
	var tablet = document.embeds["wacom-plugin"];
	if(!tablet)
		tablet = {
			pressure: undefined,
			pointerType: undefined
		};
	
	var width = el.offsetWidth;
	var height = el.offsetHeight;
	
	function limit(val) {
		return Math.max(0, Math.min(1, val));
	};
	function getPressure() {
		tablet = document.embeds["wacom-plugin"];
		if(!tablet)
		tablet = {
			pressure: undefined,
			pointerType: undefined
		};
		var result = tablet.pressure;
		if(!tablet.pointerType || tablet.pointerType == 0 || tablet.pointerType == 2)
			result = undefined;
		return result;
	}
	
	el.onmouseover = function(event) {
		if(document.onmousemove)
			return returnval;
		width = el.offsetWidth;
		height = el.offsetHeight;
		var offset = BV.getGlobalOff(el);
		var x = event.pageX - offset.x, y = event.pageY - offset.y;
		callback({event: event, x: limit(x / width), y: limit(y / height), over:true, absX: x, absY: y});
		return returnval;
	};
	el.onmouseout = function(event) {
		if(document.onmousemove)
			return returnval;
		width = el.offsetWidth;
		height = el.offsetHeight;
		var offset = BV.getGlobalOff(el);
		var x = event.pageX - offset.x, y = event.pageY - offset.y;
		callback({event: event, x: limit(x / width), y: limit(y / height), out:true, absX: x, absY: y});
		return returnval;
	};
	el.onmousemove = function(event) {
		if(document.onmousemove)
			return returnval;
		width = el.offsetWidth;
		height = el.offsetHeight;
		var offset = BV.getGlobalOff(el);
		var x = event.pageX - offset.x, y = event.pageY - offset.y;
		callback({event: event, x: limit(x / width), y: limit(y / height), move:true, absX: x, absY: y});
		return returnval;
	};
	el.onmousedown = function(event) {
		width = el.offsetWidth;
		height = el.offsetHeight;
		var offset = BV.getGlobalOff(el);
		var x = event.pageX - offset.x, y = event.pageY - offset.y;
		var lastX = x, lastY = y;
		var buttoncode = event.button;
		callback({event: event, x: limit(x / width), y: limit(y / height), dragdone:false, absX: x, absY: y, code: event.button, dX: 0, dY: 0, down: true, pressure: getPressure()});
		document.onmousemove = function(event) {
			x = event.pageX - offset.x, y = event.pageY - offset.y;
			callback({event: event, x: limit(x / width), y: limit(y / height), dragdone:false, absX: x, absY: y, code: buttoncode, dX: x - lastX, dY: y - lastY, pressure: getPressure(),
			pageX: event.pageX, pageY: event.pageY});
			lastX = x, lastY = y;
			return returnval;
		}
		document.onmouseup = function(event) {
			callback({event: event, x: limit(x / width), y: limit(y / height), dragdone:true, absX: x, absY: y, code: buttoncode});
			document.onmousemove = undefined;
			document.onmouseup = undefined;
			return returnval;
		};
		
		return returnval;
	}
	el.ontouchstart = function(event) {
		if(event.touches.length != 1)
			return;
		var offset = BV.getGlobalOff(el);
		var x = event.touches[0].pageX - offset.x, y = event.touches[0].pageY - offset.y;
		var lastX = x, lastY = y;
		width = el.offsetWidth;
		height = el.offsetHeight;
		var valx = Math.max(0, Math.min(1, x/width));
		var valy = Math.max(0, Math.min(1, y/height));
		callback({event: event, x:valx, y:valy, dragdone:false, absX:x, absY:y, code: 0, down: true, dX: 0, dY: 0, touch:true});
		document.ontouchmove = function(event) {
			if(event.touches.length != 1)
				return;
			x = event.touches[0].pageX - offset.x, y = event.touches[0].pageY - offset.y;
			valx = Math.max(0, Math.min(1, x/width));
			valy = Math.max(0, Math.min(1, y/height));
			callback({event: event, x:valx, y:valy, dragdone:false, absX:valx*width, absY:valy*height, code: 0, dX: x - lastX, dY: y - lastY, touch:true});
			lastX = x, lastY = y;
			return returnval;
		}
		document.ontouchend = function(event) {
			callback({event: event, x:valx, y:valy, dragdone:true, absX:valx*width, absY:valy*height, code: 0, dX: x - lastX, dY: y - lastY, touch:true});
			document.ontouchmove = undefined;
			document.ontouchend = undefined;
			return returnval;
		};
		
		return returnval;
	}
	
	wheel = function(event) {
		var delta = 0;
		if (!event)
			event = window.event;
		if (event.wheelDelta) {
			delta = event.wheelDelta/120;
		}
		else if (event.detail) {
			delta = -event.detail/3;
		}
		
		width = el.offsetWidth;
		height = el.offsetHeight;
		var offset = BV.getGlobalOff(el);
		var x = event.pageX - offset.x, y = event.pageY - offset.y;
		callback({event: event, x: limit(x / width), y: limit(y / height), delta: delta, absX: x, absY: y});
	
	};
	el.onmousewheel = wheel;
	el.addEventListener('DOMMouseScroll', wheel, false);
	
	return true;
};

//label, func, start, end, startval, onlyfinal
BV.pcSlider = function(params) {
	var disabled = false;
	var useSpline = false;
	var interpolator;
	
	if(!params.label || !params.func)
		return;
	if(params.start != 0 && params.end != 0 && params.startval != 0)
		if(!params.start || !params.end || !params.startval)
			return;
	if(params.start >= params.end)
		return;
	
	if(params.spline) {
		useSpline = true;
		interpolator = new SplineInterpolator(params.spline);
	}
	
	var div = document.createElement("div");
	var labelcaption = params.label;
	var label = document.createElement("div");
	var control = document.createElement("div");
	var control_inner = document.createElement("div");
	
	var width = params.w;
	var height = params.h;
	var start = params.start;
	var end = params.end;
	var val = Math.max(params.start, Math.min(params.end, params.startval));
	val = (val-params.start)/(params.end-params.start);
	if(useSpline) {
		val = Math.max(0, Math.min(1, params.startval));
	}
	
	var hover = false;
	
	div.appendChild(control);
	div.appendChild(label);
	control.appendChild(control_inner);
	div.className = "sliderWrapper";
	control.className = "sliderInner";
	div.style.overflow = "hidden";
	div.style.cursor = "default";
	div.style.position = "relative";
	div.style.width = width+"px";
	div.style.height = height+"px";
	div.style.backgroundColor = "#999";
	div.style.cursor = "default";
	control.style.backgroundColor = "#aaa";
	label.innerHTML = params.label;
	//label.style.textShadow= "#fff 0px 0px 5px";
	
	control.style.position = "absolute";
	control.style.left = 0;
	control.style.top = 0;
	control.style.width = (val*width)+"px";
	control.style.height = height+"px";
	
	label.style.position = "absolute";
	label.style.left = "5px";
	label.style.top = "5px";
	label.style.fontSize = (height-12)+"px";
	
	function getOutsideVal() {
		var result = start+val*(end-start);
		if(useSpline) {
			result = interpolator.interpolate(val);
		}
		return result;
	}
	
	function updateLabel() {
		label.innerHTML = labelcaption + " : " + parseInt(getOutsideVal(val));
		control.style.width = (val*width)+"px";
	};
	updateLabel();
	div.isHover = function() {
		return hover;
	}
	div.listener = function(v) {
		if(disabled === true)
			return;
		if(v.over || v.move) {
			if(!hover) {
				hover = true;
			}
		}
		if(v.out) {
			if(hover) {
				hover = false;
			}
		}
		if(v.dragdone == undefined)
			return;
		val = v.x;

		updateLabel();
		div.style.backgroundColor = "#555";
		if(!params.onlyfinal || v.dragdone === true)
		{
			params.func(getOutsideVal(val));
		}
		if(v.dragdone)
		{
			div.style.backgroundColor = "#999";
		}
		
	};
	BV.attachMouseListener(div, div.listener);
	div.getValue = function() {
		return getOutsideVal(val);
	};
	div.disable = function() {	
		disabled = true;
	};
	
	return div;
};

BV.pcColorSlider = function(p_w, p_svh, p_h, p_startval, p_func) {
	var div = document.createElement("div");
	/*div.style.border = "1px solid #fff";
	div.style.borderRight = "1px solid #333";
	div.style.borderBottom = "1px solid #333";*/
	div.style.position = "relative";
	div.className = "colorSlider";
	var width = p_w;
	var svheight = p_svh;
	var height = p_h;
	var func = p_func;
	var color = BV.ColorConverter.toHSV(p_startval);
	var SVcanvas = BV.createCanvas();
	SVcanvas.width = width;
	SVcanvas.height = svheight;
	BV.css(SVcanvas, {
		display : "block",
		position : "absolute",
		top : "1px",
		left : "1px",
		cursor: "crosshair",
		boxShadow: "1px 1px 5px rgba(0,0,0,0.4)"
	});
	
	var divH = document.createElement("div");
	var divPreview = document.createElement("div");
	var controlH = document.createElement("div");
	
	function createHbg() {
		var im = new Image();
		var cv = BV.createCanvas();
		cv.width = width;
		cv.height = height;
		ctx = cv.getContext("2d");
		var gradH = ctx.createLinearGradient(0, 0, width, 0);
		for(var i = 0; i < 1; i+=0.01) {
			var col = BV.ColorConverter.toRGB(new HSV(i*360, 100,  100));
			var ha = (parseInt(col.r)).toString(16);
			var hb = (parseInt(col.g)).toString(16);
			var hc = (parseInt(col.b)).toString(16);
			if(ha.length == 1)
				ha = "0" + ha;
			if(hb.length == 1)
				hb = "0" + hb;
			if(hc.length == 1)
				hc = "0" + hc;
			gradH.addColorStop(i, '#'+ha+hb+hc);
		}
		ctx.fillStyle = gradH;
		ctx.fillRect(0, 0, width, height);
		
		im.src = cv.toDataURL("image/png");
		return im;
	}
	divH.appendChild(createHbg());
	divH.appendChild(controlH);
	
	
	function updateSVcanvas() {
		ctx = SVcanvas.getContext("2d");
		for(var i = 0; i < svheight; i+=1) {
			var gradient1 = ctx.createLinearGradient(0, 0, width, 0);
			
			var colleft = BV.ColorConverter.toRGB(new HSV(color.h, 1,  100-(i/svheight*100.0)));
			var colright = BV.ColorConverter.toRGB(new HSV(color.h, 100,  100-(i/svheight*100.0)));
			gradient1.addColorStop(0,   '#'+BV.ColorConverter.toHexString(colleft));
			gradient1.addColorStop(1,   '#'+BV.ColorConverter.toHexString(colright));
			ctx.fillStyle = "#ff0000";//needed for chrome...otherwise alpha problem
			ctx.fillStyle = gradient1;
			ctx.fillRect(0, i, width, 1);
		}
		//draw Control
		ctx.strokeStyle = color.v > 70 ? "rgba(0,0,0,1)" : "rgba(255,255,255,1)";
		ctx.fillStyle = "rgba(0,0,0,0)";
		ctx.beginPath();
		ctx.arc(color.s/100*width,(100-color.v)/100*svheight,5,0,Math.PI*2,true);
		ctx.closePath();
		ctx.stroke();
		ctx.fill();
	}
	
	function setColPreview() {
		var rgb = BV.ColorConverter.toRGB(color);
		rgb.r = parseInt(rgb.r);
		rgb.g = parseInt(rgb.g);
		rgb.b = parseInt(rgb.b);
		divPreview.style.backgroundColor = "rgb("+rgb.r+","+rgb.g+","+rgb.b+")";
	}
	
	updateSVcanvas();
	div.style.width = width+"px";
	div.oncontextmenu = function(){return false;};
	div.appendChild(SVcanvas);
	div.appendChild(divH);
	div.appendChild(divPreview);
	divPreview.style.width = width+"px";
	divPreview.style.height = height+"px";
	divPreview.style.position = "absolute";
	divPreview.style.top = (height+svheight+3)+"px";
	divPreview.style.left = "1px";
	setColPreview();
	
	BV.css(divH, {
		overflow: "hidden",
		position: "relative",
		width: width+"px",
		height: height+"px",
		position: "absolute",
		top: (svheight+2)+"px",
		left: "1px",
		cursor: "crosshair",
		boxShadow: "1px 1px 5px rgba(0,0,0,0.4)"
	});
	
	divH.className = "svSlider";
	controlH.style.width = 1+"px";
	controlH.style.height = height+"px";
	controlH.style.backgroundColor = "#000";
	controlH.style.borderLeft = "1px solid #fff";
	controlH.style.position = "absolute";
	controlH.style.top = 0;
	controlH.style.left = parseInt(color.h/360*width-1)+"px";
	BV.attachMouseListener(SVcanvas, function(val) {
		if(val.dragdone == undefined)
			return;
		if(val.down ) {
			BV.css(SVcanvas, {
				boxShadow: "0px 0px 5px rgba(255,255,255,1)",
				border: "1px solid #fff",
				marginLeft: "-1px",
				marginTop: "-1px"
			});
		} else if(val.dragdone || val.up || val.out) {
			BV.css(SVcanvas, {
				boxShadow: "1px 1px 5px rgba(0,0,0,0.4)",
				border: "",
				marginLeft: "0",
				marginTop: "0"
			});
		}
		color = new HSV(color.h, val.x*100, 100-val.y*100);
		updateSVcanvas();
		setColPreview();
		func(BV.ColorConverter.toRGB(color));
	});
	BV.attachMouseListener(divH, function(val) {
		if(val.dragdone == undefined)
			return;
		if(val.down ) {
			BV.css(divH, {
				boxShadow: "0px 0px 5px rgba(255,255,255,1)",
				border: "1px solid #fff",
				marginLeft: "-1px",
				marginTop: "-1px"
			});
		} else if(val.dragdone || val.up || val.out) {
			BV.css(divH, {
				boxShadow: "1px 1px 5px rgba(0,0,0,0.4)",
				border: "",
				marginLeft: "0",
				marginTop: "0"
			});
		}
		color = new HSV(val.x*359, color.s, color.v);
		controlH.style.left = parseInt(color.h/359*width-1)+"px";
		updateSVcanvas();
		setColPreview();
		func(BV.ColorConverter.toRGB(color));
	});
	

	div.setColor = function(c) {
		color = BV.ColorConverter.toHSV(c);
		controlH.style.left = parseInt(color.h/359*width-1)+"px";
		updateSVcanvas();
		setColPreview();
	};
	div.getColor = function() {
		return BV.ColorConverter.toRGB(color);
	};
	
	var pickerButton = document.createElement("div");
	var picking = false;
	pickerButton.title = "Color Picker";
	pickerButton.style.background = "url(picker.png) no-repeat 0 0";
	pickerButton.style.backgroundColor = "#dddddd";
	pickerButton.style.width = "30px";
	pickerButton.style.height = "30px";
	pickerButton.style.position = "absolute";
	pickerButton.style.top = "133px";
	pickerButton.style.left = "0px";
	pickerButton.style.cursor = "pointer";
	pickerButton.style.opacity = "0.8";
	div.pickCallback = function(){};
	pickerButton.onclick = function() {
		if(picking == false) {
			pickerButton.style.backgroundColor = "#fff";
			pickerButton.style.opacity = "1.0";
			picking = true;
			div.pickCallback(true);
		} else {
			div.pickCallback(false);
			div.pickingDone();
		}
	}
	pickerButton.onmouseover = function() {
		if(picking === false) {
			pickerButton.style.backgroundColor = "#eee";
			pickerButton.style.opacity = "1";
		}
	}
	pickerButton.onmouseout = function() {
		if(picking === false) {
			pickerButton.style.backgroundColor = "#ddd";
			pickerButton.style.opacity = "0.8";
		}
	}
	div.appendChild(pickerButton);
	
	div.pickingDone = function() {
		picking = false;
		pickerButton.style.opacity = "0.8";
		pickerButton.style.backgroundColor = "#dddddd";
	}
	
	return div;
};

BV.pcCanvas = function(width, height) {
	var div = document.createElement("div");
	div.style.overflow = "hidden";
	div.style.position = "relative";
	var layers = [];
	var history = [];
	var maxLayers = 8;
	var pickCanvas = BV.createCanvas();
	pickCanvas.width = 1;
	pickCanvas.height = 1;
	
	function init(width, height) {
		width = Math.max(width, 1);
		height = Math.max(height, 1);
		div.width = width;
		div.height = height;
		div.style.width = width+"px";
		div.style.height = height+"px";
		
	};
	init(width, height);
	
	div.getLayerCount = function() {
		return layers.length;
	}
	//restore image from local storage
	div.restore = function() {
		layers = [];
		history = [];
		//localStorage.removeItem("width");
		//localStorage.removeItem("height");
		if(!(localStorage.layers > 0))
			return false;
		init(localStorage.width, localStorage.height);
		
		for(var i = 0; i < localStorage.layers; i++) {
			//ctx.globalAlpha = 1.0;//parseFloat(layers[i].style.opacity);
			//localStorage["im"+i] = layers[i].toDataURL("image/png");
			//localStorage["opacity"+i] = "" + layers[i].style.opacity;
			
			function dostuff(val) {
				div.addLayer();
				var ctx = div.getLayerContext(val);
				var loadedIm = new Image();
				loadedIm.src = localStorage["im"+val];
				function waitload()
				{
					if(loadedIm.complete)
						ctx.drawImage(loadedIm, 0, 0);
					else
						setTimeout(waitload, 10);
				};
				waitload();
				div.layerOpacity(val, parseFloat(localStorage["opacity"+val]) );
			};
			dostuff(i);
		}
		
		/*div.addLayer();
		var ctx = div.getLayerContext(0);
		var loadedIm = new Image();
		loadedIm.src = localStorage.im;
		function waitload()
		{
			if(loadedIm.complete)
				ctx.drawImage(loadedIm, 0, 0);
			else
				setTimeout(waitload, 10);
		};
		waitload();*/

		return true;
	};
	
	div.store = function() {
		var result = false;
		var i = 0;
		while(i < 50) {
			localStorage.removeItem("opacity"+i++);
			localStorage.removeItem("im"+i++);
		}
		
		try {
			localStorage.width = div.width;
			localStorage.height = div.height;	
			localStorage.layers = layers.length;
			
			for(var i = 0; i < layers.length; i++)
			{
				//ctx.globalAlpha = 1.0;//parseFloat(layers[i].style.opacity);
				localStorage.setItem("im"+i, layers[i].toDataURL("image/png"));
				localStorage["opacity"+i] = "" + layers[i].style.opacity;
			}
			result = true;
		}
		catch(e) {
			localStorage.removeItem("layers");
			localStorage.removeItem("width");
			localStorage.removeItem("height");
			while(i < 50)
			{
				localStorage.removeItem("opacity"+i++);
				localStorage.removeItem("im"+i++);
			}
			result = false;
		}
		
		
		return result;
	};
	
	div.style.backgroundImage = "url(" + BV.createChecker(8) + ")";
	
	div.resize = function(w, h) {
		if(!w || !h || (w === div.width && h === div.height)) {
			return false;
		}
		w = Math.max(w, 1);
		h = Math.max(h, 1);

		if(w <= div.width && h <= div.height) {
			var base2 = {expw: 1, exph: 1, minw: 1, minh: 1, w:0, h:0};
			while(Math.pow(2,base2.expw) < div.width) {
				base2.expw++;
			}
			while(Math.pow(2,base2.exph) < div.height) {
				base2.exph++;
			}
			var scalew = w/div.width;
			var scaleh = h/div.height;
			var minw = scalew * Math.pow(2,base2.expw);
			var minh = scaleh * Math.pow(2,base2.exph);
			while(Math.pow(2,base2.minw) < minw) {
				base2.minw++;
			}
			while(Math.pow(2,base2.minh) < minh) {
				base2.minh++;
			}
			
			var tmp1 = BV.createCanvas();
			var tmp2 = BV.createCanvas();
			base2.w = Math.pow(2,base2.expw);
			base2.h = Math.pow(2,base2.exph);
			tmp1.width = base2.w;
			tmp1.height = base2.h;
			tmp2.width = base2.w;
			tmp2.height = base2.h;
			
			var ew, eh;
			var temp; //for switching
			var buffer1 = tmp1, buffer2 = tmp2, state = false;
			
			for(var i = 0; i < layers.length; i++) {
				tmp1.getContext("2d").clearRect(0, 0, tmp1.width, tmp1.height);
				tmp2.getContext("2d").clearRect(0, 0, tmp2.width, tmp2.height);
				ew = base2.expw-1;
				eh = base2.exph-1;
				buffer2 = layers[i];
				var counter = 0;
				for(; ew >= base2.minw || eh >= base2.minh; ew--, eh--) {
					counter++;
					buffer1.getContext("2d").clearRect(0,0,base2.w,base2.h);
					buffer1.getContext("2d").drawImage(buffer2, 0, 0, (ew >= base2.minw) ? buffer2.width/2 : buffer2.width, (eh >= base2.minh) ? buffer2.height/2 : buffer2.height);
					
					if(!state) {
						buffer1 = tmp2;
						buffer2 = tmp1;
					} else {
						buffer1 = tmp1;
						buffer2 = tmp2;
					}
					state = !state;
				}
				if(counter === 0) {
					buffer1.getContext("2d").drawImage(layers[i], 0, 0);
					buffer2 = buffer1;
				}
				var ratiow = div.width/base2.w;
				var ratioh = div.height/base2.h;
				var finalscaleW = minw/Math.pow(2,base2.minw), finalscaleH = minh/Math.pow(2,base2.minh);
				layers[i].width = w;
				layers[i].height = h;
				layers[i].getContext("2d").drawImage(buffer2, 0, 0, buffer2.width * finalscaleW, buffer2.height * finalscaleH);
			}
			buffer1 = undefined;
			buffer2 = undefined;
			delete tmp1;
			delete tmp2;
		} else if(w >= div.width && h >= div.height) {
			var tmp1 = BV.createCanvas();
			var tmp2 = BV.createCanvas();
			tmp1.width = w;
			tmp1.height = h;
			tmp2.width = w;
			tmp2.height = h;
			var scaleX = 1, endScaleX = w/div.width;
			var scaleY = 1, endScaleY = h/div.height;
			var maxX = scaleX, maxY = scaleY;
			while(maxX <= endScaleX) {
				maxX *= 2;
			}
			while(maxY <= endScaleY) {
				maxY *= 2;
			}
			maxX /= 2;
			maxY /= 2;
			var buffer1 = tmp1, buffer2 = tmp2, state = false;
			function switchBuffers() {
				if(!state) {
					buffer1 = tmp2;
					buffer2 = tmp1;
				} else {
					buffer1 = tmp1;
					buffer2 = tmp2;
				}
				state = !state;
			}
			for(var i = 0; i < layers.length; i++) {
				tmp1.getContext("2d").clearRect(0, 0, tmp1.width, tmp1.height);
				tmp2.getContext("2d").clearRect(0, 0, tmp2.width, tmp2.height);
				scaleX = 2;
				scaleY = 2;
				buffer2 = layers[i];
				var counter = 0;
				while(scaleX <= maxX || scaleY <= maxY) {
					buffer1.getContext("2d").clearRect(0, 0, buffer1.width, buffer1.height);
					buffer1.getContext("2d").drawImage(buffer2, 0, 0, buffer2.width * ((scaleX <= maxX) ? 2 : 1), buffer2.height * ((scaleY <= maxY) ? 2 : 1) );
					
					scaleX *= 2;
					scaleY *= 2;
					counter++;
					switchBuffers();
				}
				if(counter == 0) {
					buffer1.getContext("2d").drawImage(layers[i], 0, 0);
					buffer2 = buffer1;
				}
				var finalScaleX = endScaleX / maxX;
				var finalScaleY = endScaleY / maxY;
				layers[i].width = w;
				layers[i].height = h;
				layers[i].getContext("2d").drawImage(buffer2, 0, 0, buffer2.width * finalScaleX, buffer2.height*finalScaleY);
			}
			
			
		} else {
			div.resize(w+0, div.height+0);
			div.resize(w+0, h+0);
			
			/*(function() {
				var ctemp = BV.createCanvas();
				ctemp.width = w;
				ctemp.height = h;
				for(var i = 0; i < layers.length; i++) {
					ctemp.getContext("2d").clearRect(0,0,w,h);
					ctemp.getContext("2d").drawImage(layers[i], 0, 0, w, h);
					layers[i].width = w;
					layers[i].height = h;
					layers[i].getContext("2d").drawImage(ctemp, 0, 0);
				}
				delete ctemp;
			})();*/
			
		}
		div.width = w;
		div.height = h;
		div.style.width = w+"px";
		div.style.height = h+"px";
		return true;
	};
	
	div.resizeCanvas = function(p) {
		var newW = 1, newH = 1;
		var offX = 0, offY = 0;
		newW = parseInt(p.left) + parseInt(div.width) + parseInt(p.right);
		newH = parseInt(p.top) + parseInt(div.height) + parseInt(p.bottom);
		if(newW < 1 || newH < 1)
			return;
		offX = p.left;
		offY = p.top;
		for(var i = 0; i < layers.length; i++) {
			var ctemp = BV.createCanvas();
			ctemp.width = div.width;
			ctemp.height = div.height;
			ctemp.getContext("2d").drawImage(layers[i], 0, 0);
			layers[i].getContext("2d").clearRect(0, 0, div.width, div.height);
			layers[i].width = newW;
			layers[i].height = newH;
			layers[i].getContext("2d").drawImage(ctemp, offX, offY);
		}
		
		div.width = newW;
		div.height = newH;
		div.style.width = newW+"px";
		div.style.height = newH+"px";
	}
	div.addLayer = function() {
		if(layers.length >= maxLayers)
			return false;
		var canvas = BV.createCanvas();
		canvas.width = div.width;
		canvas.height = div.height;
		layers[layers.length] = canvas;
		div.appendChild(canvas);
		canvas.style.imageRendering = "-webkit-optimize-contrast";
		canvas.style.imageRendering = "-webkit-crisp-edges";
		canvas.style.imageRendering = "crisp-edges";
		canvas.style.position = "absolute";
		canvas.style.left = 0;
		canvas.style.top = 0;
		canvas.name = "Layer " + layers.length;
		div.layerOpacity(layers.length-1, 1);
		//history
	};
	div.duplicateLayer = function(i) {
		if(!layers[i] || layers.length >= maxLayers)
			return false;
		var canvas = BV.createCanvas();
		canvas.width = div.width;
		canvas.height = div.height;
		layers.splice(i+1, 0, canvas);
		div.appendChild(canvas);
		canvas.style.position = "absolute";
		canvas.style.left = 0;
		canvas.style.top = 0;
		canvas.name = layers[i].name + " copy";
		canvas.getContext("2d").drawImage(layers[i], 0, 0);
		div.layerOpacity(i+1, layers[i].style.opacity);
		
		while(div.firstChild)
				div.removeChild(div.firstChild);
			for(var e = 0; e < layers.length; e++)
				div.appendChild(layers[e]);
	};
	div.getLayerContext = function(i) {
		if(layers[i])
			return layers[i].getContext("2d");
	};
	div.removeLayer = function(i) {
		if(layers[i]) {
			div.removeChild(layers[i]);
			layers.splice(i, 1);
		}
	};
	div.layerOpacity = function(i, o) {
		
		if(o !== 0 && (o < 0 || o > 1 || !o || !layers[i]))
			return;
		layers[i].style.opacity = o;
		if(o === 0)
			layers[i].style.display = "none";
		else if(layers[i].style.display == "none") {
			layers[i].style.display = "block";
		}
	};
	div.moveLayer = function(i, d) {
		if(layers[i]) {
			var temp = layers[i];
			layers.splice(i, 1);
			var target = Math.max(0, Math.min(i + d, layers.length));
			layers.splice(target, 0, temp);
			while(div.firstChild)
				div.removeChild(div.firstChild);
			for(var e = 0; e < layers.length; e++)
				div.appendChild(layers[e]);
		}
	};
	div.layerPos = function(i, x, y) {
		if(layers[i])
		{
			layers[i].style.left = x+"px";
			layers[i].style.top = y+"px";
		}
	};
	div.mergeLayers = function(i, j) {
		if(!layers[i] || !layers[j] || i == j)
			return;
		if(i > j) {
			var temp = i;
			i = j;
			j = temp;
		}
		var desti = i;
		var jOpacity = parseFloat(layers[j].style.opacity);
		if(jOpacity != 0 && jOpacity) {
			if(jOpacity != 1)
			{
				var imdat = layers[j].getContext("2d").getImageData(0, 0, div.width, div.height);
				for(var k = 3; k < imdat.data.length; k+=4)
					imdat.data[k] = parseInt(imdat.data[k]*jOpacity);
				layers[j].getContext("2d").putImageData(imdat, 0, 0);
			}
			layers[i].getContext("2d").drawImage(layers[j], 0, 0);
		}
		
		div.removeLayer(j);
	};
	div.rotate = function(deg) {	
		while(deg < 0) {
			deg += 360;
		}
		deg %= 360;
		if(deg %90 != 0 || deg === 0)
			return;
		var temp = BV.createCanvas();
		if(deg == 0 || deg == 180) {
			temp.width = div.width;
			temp.height = div.height;
		} else if(deg == 90 || deg == 270) {
			temp.width = div.height;
			temp.height = div.width;
		}
		var ctx = temp.getContext("2d");
		for(var i = 0; i < layers.length; i++) {
			ctx.clearRect(0,0,temp.width,temp.height);
			ctx.save();
			ctx.translate(temp.width / 2, temp.height / 2);  
			ctx.rotate(deg * Math.PI / 180);
			if(deg === 180) {
				ctx.drawImage(layers[i], -temp.width / 2, -temp.height / 2);
			} else if(deg === 90 || deg === 270) {
				ctx.drawImage(layers[i], -temp.height / 2, -temp.width / 2);
			}
			layers[i].width = temp.width;
			layers[i].height = temp.height;
			layers[i].getContext("2d").clearRect(0, 0, layers[i].width, layers[i].height);
			layers[i].getContext("2d").drawImage(temp, 0, 0);
			ctx.restore();
		}
		div.width = temp.width;
		div.height = temp.height;
		div.style.width = temp.width+"px";
		div.style.height = temp.height+"px";
	}
	div.flip = function(horizontal, vertical) {
		if(!horizontal && !vertical) {
			return;
		}
		
		var temp = BV.createCanvas();
		temp.width = div.width;
		temp.height = div.height;
		var ctx = temp.getContext("2d");
		
		for(var i = 0; i < layers.length; i++) {
			ctx.clearRect(0,0,temp.width,temp.height);
			ctx.save();
			ctx.translate(temp.width/2, temp.height/2);
			ctx.scale((horizontal ? -1 : 1), (vertical ? -1 : 1));
			ctx.drawImage(layers[i], -temp.width/2, -temp.height/2);
			layers[i].getContext("2d").clearRect(0, 0, layers[i].width, layers[i].height);
			layers[i].getContext("2d").drawImage(temp, 0, 0);
			ctx.restore();
		}
		
	}
	div.addHistory = function() {
	};
	div.undo = function() {
	};
	div.redo = function() {
	};
	div.getLayers = function() {
		var result = [];
		for(var i = 0; i < layers.length; i++)
		{
			result[i] = {
				context : layers[i].getContext("2d"),
				opacity : layers[i].style.opacity,
				name : layers[i].name
			};
		}
		
		return result;
	};
	div.setLayerName = function(i, val) {
		if(layers[i])
			layers[i].name = val;
	};
	div.getLayerName = function(i) {
		if(layers[i])
			return layers[i].name;
	};
	div.getColorAt = function(x, y)
	{
		var ctx = pickCanvas.getContext("2d");
		ctx.clearRect(0,0,1,1);
		for(var i = 0; i < layers.length; i++)
		{
			ctx.globalAlpha = parseFloat(layers[i].style.opacity);
			ctx.drawImage(layers[i], -x, -y);
		}
		var imdat = ctx.getImageData(0, 0, 1, 1);
		return new RGB(imdat.data[0], imdat.data[1], imdat.data[2]);
	};
	
	div.saveAsJPEG = function(fname) {
		var finalim = BV.createCanvas();
		finalim.width = div.width;
		finalim.height = div.height;
		var ctx = finalim.getContext("2d");
		for(var i = 0; i < layers.length; i++)
		{
			ctx.globalAlpha = parseFloat(layers[i].style.opacity);
			ctx.drawImage(layers[i], 0, 0);
		}
		
		finalim.toBlob(function(blob) {
		saveAs(
			  blob
			, fname + ".jpg"
		);
		}, "image/jpeg");
	}
	
	div.getDataURL = function() {
		var finalim = BV.createCanvas();
		finalim.width = div.width;
		finalim.height = div.height;
		var ctx = finalim.getContext("2d");
		for(var i = 0; i < layers.length; i++)
		{
			ctx.globalAlpha = parseFloat(layers[i].style.opacity);
			ctx.drawImage(layers[i], 0, 0);
		}
		return finalim.toDataURL("image/jpeg");
	}
	div.getRegion = function(x, y, cnvs) {
		var finalim = cnvs;
		var ctx = finalim.getContext("2d");
		for(var i = 0; i < layers.length; i++)
		{
			ctx.globalAlpha = parseFloat(layers[i].style.opacity);
			ctx.drawImage(layers[i], -x, -y);
		}
		return finalim;
	}
	div.getCompleteCanvas = function(factor) {
		var finalim = BV.createCanvas();
		finalim.width = Math.max(1,parseInt(div.width*factor));
		finalim.height = Math.max(1,parseInt(div.height*factor));
		var ctx = finalim.getContext("2d");
		for(var i = 0; i < layers.length; i++)
		{
			ctx.globalAlpha = parseFloat(layers[i].style.opacity);
			ctx.drawImage(layers[i], 0, 0, finalim.width, finalim.height);
		}
		return finalim;
	}
	div.getLayerIndex = function(cnvs) {
		for(var i = 0; i < layers.length; i++){
			if(layers[i] === cnvs)
				return i;
		}
		alert("not found");
	}
	
	return div;
};

BV.pcTabMenu = function(params, p_padding, p_dark, customW) {
	
	var div = document.createElement("div");
	var tabs = params
	var width = 270;
	if(customW)
		width = customW;
	div.className = "tab";
	div.style.cursor = "default";
	BV.css(div, {
		width: width+"px"
		//backgroundColor: "#f00"
	});
	//if(p_dark)
	//	div.style.backgroundColor = "#777";
		//div.style.borderTop = "1px solid #eee";
	if(!p_dark) {
		div.style.boxShadow= "";
	}
	
	var active = 0;
	for(var i = 0; i < params.length; i++)
	{
		params[i].div = document.createElement("div");
		params[i].div.className = "tabbutton";
		BV.css(params[i].div, {
			cssFloat : "left",
			width: parseInt(width/params.length)+"px",
			cursor: "pointer",
			fontWeight: "bold",
			textAlign: "center",
			//display: "inline-block",
			opacity: "1.0",
			//backgroundImage: "-webkit-gradient(linear,left bottom,left top,color-stop(0.3, rgba(179,179,179,0.5)),color-stop(0.7, rgba(94,94,94,0.7)));",
			paddingTop: p_padding+"px",
			paddingBottom: p_padding+"px"
		});
		if(i == active) {
			params[i].div.style.backgroundColor= "#ccc";
			params[i].div.style.cursor = "";
		}
			
		/*if(params[i].divInner) {
			params[i].div.appendChild(params[i].divInner);
		} else {*/
			params[i].div.innerHTML = params[i].name;
		//}
		
		if(i != active)
		{
			params[i].clicked = false;
			params[i].hide();
			params[i].div.style.backgroundColor= "";
			//params[i].div.style.fontWeight= "";
			params[i].div.style.color= "#444";
			params[i].div.style.opacity= "0.7";
			if(params[i].divInner)
				params[i].divInner.className = "tabIm";
		}
		else
		{
			params[i].clicked = false;
			params[i].show();
			params[i].div.style.backgroundColor= "#fff";
			//params[i].div.style.fontWeight= "bold";
			params[i].div.style.color= "#000";
			params[i].div.style.opacity= "1.0";
			if(params[i].divInner)
				params[i].divInner.className = "tabImSel";
		}
		
		params[i].div.onmousedown = function()
		{
			for(var e = 0 ; e < params.length; e++)
			{
				if(params[e].div != this)
				{
					params[e].clicked = false;
					/*params[e].hide();
					params[e].div.style.backgroundColor= "";
					//params[e].div.style.fontWeight= "";
					params[e].div.style.color= "#444";
					params[e].div.style.opacity= "0.7";*/
				}
				else
				{
					params[e].clicked = true;
					/*params[e].show();
					params[e].div.style.backgroundColor= "#fff";
					//params[e].div.style.fontWeight= "bold";
					params[e].div.style.color= "#000";
					params[e].div.style.opacity= "1.0";*/
				}
			}
		};
		params[i].div.onmouseup = function() {
			var found = false;
			for(var e = 0 ; e < params.length; e++)
			{
				if(params[e].div != this)
				{
					params[e].clicked = false;
				}
				else if(params[e].clicked && e != active)
				{
					params[e].clicked = false;
					found = true;
				}
			}
			if(found) {
				for(e = 0 ; e < params.length; e++)
				{
					if(params[e].div != this)
					{
						params[e].hide();
						params[e].div.style.backgroundColor= "";
						//params[e].div.style.fontWeight= "";
						params[e].div.style.color= "#444";
						params[e].div.style.opacity= "0.7";
						params[e].div.style.cursor = "pointer";
						if(params[e].divInner)
							params[e].divInner.className = "tabIm";
					}
					else
					{
						params[e].show();
						params[e].div.style.backgroundColor= "#fff";
						//params[e].div.style.fontWeight= "bold";
						params[e].div.style.color= "#000";
						params[e].div.style.opacity= "1.0";
						params[e].div.style.cursor = "";
						if(params[e].divInner)
							params[e].divInner.className = "tabImSel";
						active = e;
					}
				}
			}
		}
		
		div.appendChild(params[i].div);
	}
	var cleardiv = document.createElement("div");
	cleardiv.style.clear = "both";
	div.appendChild(cleardiv);
	div.show = function(index)
	{
		if(index == active)
			return;
		tabs[index].div.onmousedown();
		tabs[index].div.onmouseup();
		active = index;
	};
	return div;
}

BV.pcInfoBoxTabMenu = function(params, p_padding, p_dark, customW) {
	
	var div = document.createElement("div");
	var tabs = params
	var width = 270;
	if(customW)
		width = customW;
	div.className = "infotab";
	BV.css(div, {
		width: width+"px"
		//backgroundColor: "#f00"
	});
	//if(p_dark)
	//	div.style.backgroundColor = "#777";
		//div.style.borderTop = "1px solid #eee";

	div.style.boxShadow= "";
	
	var active = 0;
	for(var i = 0; i < params.length; i++)
	{
		params[i].div = document.createElement("div");
		params[i].div.className = "infotabbutton";
		BV.css(params[i].div, {
			cssFloat : "left",
			width: parseInt(width/params.length)+"px",
			cursor: "pointer",
			textAlign: "center",
			//display: "inline-block",
			//backgroundImage: "-webkit-gradient(linear,left bottom,left top,color-stop(0.3, rgba(179,179,179,0.5)),color-stop(0.7, rgba(94,94,94,0.7)));",
			paddingTop: p_padding+"px",
			paddingBottom: p_padding+"px",
			fontSize: "14px"
		});
		if(i == active){
			params[i].div.style.backgroundColor= "#e9e9e9";
			params[i].div.style.cursor = "";
		}
			
		/*if(params[i].divInner) {
			params[i].div.appendChild(params[i].divInner);
		} else {*/
			params[i].div.innerHTML = params[i].name;
		//}
		if(i != active)
		{
			params[i].clicked = false;
			params[i].hide();
			params[i].div.style.backgroundColor= "";
			params[i].div.style.color= "#636363";
			params[i].div.style.boxShadow= "";
			if(params[i].divInner)
				params[i].divInner.className = "tabIm";
		}
		else
		{
			params[i].clicked = false;
			params[i].show();
			params[i].div.style.backgroundColor= "#fff";
			params[i].div.style.color= "#555";
			params[i].div.style.boxShadow= "0px -2px 0px rgba(0,0,0,0.2)";
			if(params[i].divInner)
				params[i].divInner.className = "tabImSel";
		}
		
		params[i].div.onmousedown = function()
		{
			for(var e = 0 ; e < params.length; e++)
			{
				if(params[e].div != this)
				{
					params[e].clicked = false;
				}
				else
				{
					params[e].clicked = true;
				}
			}
			return false;
		};
		params[i].div.onmouseup = function() {
			var found = false;
			for(var e = 0 ; e < params.length; e++)
			{
				if(params[e].div != this)
				{
					params[e].clicked = false;
				}
				else if(params[e].clicked && e != active)
				{
					params[e].clicked = false;
					found = true;
				}
			}
			if(found) {
				for(e = 0 ; e < params.length; e++)
				{
					if(params[e].div != this)
					{
						params[e].hide();
						params[e].div.style.backgroundColor= "";
						params[e].div.style.color= "#636363";
						params[e].div.style.boxShadow= "";
						params[e].div.style.cursor = "pointer";
					}
					else
					{
						params[e].show();
						params[e].div.style.backgroundColor= "#fff";
						params[e].div.style.color= "#555";
						params[e].div.style.boxShadow=  "0px -2px 0px rgba(0,0,0,0.2)";
						params[e].div.style.cursor = "";
						active = e;
					}
				}
			}
		}
		
		div.appendChild(params[i].div);
	}
	var cleardiv = document.createElement("div");
	cleardiv.style.clear = "both";
	div.appendChild(cleardiv);
	div.show = function(index)
	{
		if(index == active)
			return;
		tabs[index].div.onmousedown();
		tabs[index].div.onmouseup();
		active = index;
	};
	return div;
}

BV.pcLayerManager = function(p_canvas, p_func) {
	var canvas = p_canvas;
	var layers = [];
	var layerHeight = 35;
	var layerSpacing = 0;
	var width = 250;
	
	var updatefunc = p_func;
	
	var clayers = canvas.getLayers();
	var selected = clayers.length-1;
	var div = document.createElement("div");
	div.style.marginRight = "10px";
	div.style.marginBottom = "10px";
	div.style.marginLeft = "8px";
	div.style.marginTop = "13px";
	div.style.cursor = "default";
	var listdiv = document.createElement("div");
	BV.css(listdiv, {
		width: width+"px",
		height: "500px",
		position: "relative",
		backgroundColor: "rgb( 222, 222,222)"
	});
	
	var checkers = BV.createChecker(4);
	
	
	var regularContainer = document.createElement("div");
	var dragContainer = document.createElement("div");
	
	function disableButtons() {
		addnew.disabled = true;
		duplicate.disabled = true;
		remove.disabled = true;
		merge.disabled = true;
	}
	function enableButtons() {
		addnew.disabled = false;
		duplicate.disabled = false;
		remove.disabled = false;
		merge.disabled = false;
	}
	div.disableButtons = disableButtons;
	div.enableButtons = enableButtons;
	var addnew = document.createElement("button");
	var duplicate = document.createElement("button");
	var merge = document.createElement("button");
	var remove = document.createElement("button");
	function createButtons()
	{
		var div = document.createElement("div");
		
		
		addnew.innerHTML = "New";
		duplicate.innerHTML = "Duplic.";
		merge.innerHTML = "Merge";
		remove.innerHTML = "Delete";
		addnew.style.width = "60px";
		addnew.style.marginRight = "4px";
		duplicate.style.width = "60px";
		duplicate.style.marginRight = "4px";
		merge.style.width = "60px";
		merge.style.marginRight = "4px";
		remove.style.width = "60px";
		div.appendChild(addnew);
		div.appendChild(duplicate);
		div.appendChild(merge);
		div.appendChild(remove);
		remove.style.marginBottom= "8px";
		
		
		
		addnew.onclick = function()
		{
			if(canvas.addLayer() === false)
				return;
			clayers = canvas.getLayers();
			selected = clayers.length-1;
			createLayerList();
			updatefunc(selected);
		}
		duplicate.onclick = function()
		{
			if(canvas.duplicateLayer(selected)===false)
				return;
			clayers = canvas.getLayers();
			selected++;
			createLayerList();
			updatefunc(selected);
		}
		remove.onclick = function()
		{
			if(layers.length <= 1)
				return;
			disableButtons();
			BV.popup({
				target: pcWeb,
				message: "Do you really want to remove the layer<br/>\"<b>" + clayers[selected].name + "</b>\"?",
				type: "trash",
				buttons: ["Yes", "No"],
				callback: function(result) {
					enableButtons();
					if(result != "Yes")
						return;
					canvas.removeLayer(selected);
					if(selected > 0)
						selected--;
					clayers = canvas.getLayers();
					createLayerList();
					updatefunc(selected);
				}
			});
		}
		merge.onclick = function()
		{
			if(selected <= 0)
				return;
			canvas.mergeLayers(selected, selected-1);
			clayers = canvas.getLayers();
			selected--;
			createLayerList();
			updatefunc(selected);
		}
		
		return div;
	};
	div.appendChild(createButtons());
	
	function updateThumbs() {
		for(var i = 0; i < layers.length; i++) {
			function stuff(i) {
				var thc = layers[i].thumb.getContext("2d");
				thc.drawImage(clayers[layers[i].spot].context.canvas, 0, 0, layers[i].thumb.width, layers[i].thumb.height);
			}
			stuff(i);
		}
	}
	
	function createLayerList() {
		function createLayerEntry(index) {
			var layerName = clayers[index].name;
			var opacity = clayers[index].opacity;
			var layercanvas = clayers[index].context.canvas;
			
			var layer = document.createElement("div");
			layers[index] = layer;
			layer.posY = ((clayers.length-1)*35-index*35);
			BV.css(layer, {
				width: "250px",
				height: "34px",
				backgroundColor: "rgb( 220, 220, 220)",
				border: "1px solid #888",
				position: "absolute",
				left: "0 px",
				top: layer.posY+"px",
				transition: "all 0.1s linear"
			});
			var innerLayer = document.createElement("div");
			BV.css(innerLayer, {
				position: "relative"
			});
			
			var container1 = document.createElement("div");
			BV.css(container1, {
				width: "250px",
				height: "34px"
			});
			var container2 = document.createElement("div");
			layer.appendChild(innerLayer);
			innerLayer.appendChild(container1);
			innerLayer.appendChild(container2);
			
			layer.spot = index;
			
			//thumb
			{
				layer.thumb = BV.createCanvas();
				var thumbDimensions = BV.fitInto(32, 32, layercanvas.width, layercanvas.height);
				layer.thumb.width = thumbDimensions.width;
				layer.thumb.height = thumbDimensions.height;
				var thc = layer.thumb.getContext("2d");
				thc.drawImage(layercanvas, 0, 0, layer.thumb.width, layer.thumb.height);
				BV.css(layer.thumb, {
					position: "absolute",
					left: (1 + (32-layer.thumb.width)/2) + "px",
					top: (1 + (32-layer.thumb.height)/2) + "px",
					backgroundImage: "url("+checkers+")"
				});
			}
			
			//layerlabel
			{
				layer.label = document.createElement("div");
				layer.lname = layerName;
				layer.label.appendChild(document.createTextNode(layer.lname));

				BV.css(layer.label, {
					position: "absolute",
					left: (1+32+5) + "px",
					top: 1 + "px",
					fontSize: "13px",
					width: "180px",
					height: "20px",
					overflow: "hidden",
					color: "#666"
				});
			}
			//layerlabel
			{
				layer.opacityLabel = document.createElement("div");
				layer.opacity = opacity;
				layer.opacityLabel.appendChild(document.createTextNode(parseInt(layer.opacity*100)+"%"));

				BV.css(layer.opacityLabel, {
					position: "absolute",
					left: (250-1-5-50) + "px",
					top: 1 + "px",
					fontSize: "13px",
					textAlign: "right",
					width: "50px"
				});
			}
			//sliderLine
			{
				var sliderLine = document.createElement("div");

				BV.css(sliderLine, {
					position: "absolute",
					left: (1+32+5) + "px",
					top: 23 + "px",
					height: "0px",
					borderTop: "1px solid #444",
					borderBottom: "1px solid #aaa",
					width: "206px"
				});
			}
			//sliderPoint
			{
				var sliderPoint = document.createElement("div");
				sliderPoint.pos = 0;
				sliderPoint.timeout = {};
				var tempPos = 0;
				function calcSliderPos() {
					sliderPoint.pos = parseInt(layer.opacity*196) + (1+32+5);
				}
				function updateOpacity() {
					layer.opacity = Math.max(0,Math.min(1,(sliderPoint.pos-(1+32+5))/196));
					layer.opacityLabel.innerHTML = "";
					layer.opacityLabel.appendChild(document.createTextNode(parseInt(layer.opacity*100)+"%"));
					calcSliderPos();
					sliderPoint.style.left = sliderPoint.pos + "px";
					
				}
				calcSliderPos();
				BV.css(sliderPoint, {
					position: "absolute",
					left: (sliderPoint.pos) + "px",
					top: 23 + "px",
					height: "0px",
					backgroundColor: "#444",
					width: "14px",
					height: "14px",
					marginTop: "-5px",
					WebkitBorderRadius: "7px",
					borderRadius: "7px",
					cursor: "move"
				});
				BV.attachMouseListener(sliderPoint, function(v) {
					if(v.down) {
						tempPos = sliderPoint.pos;
						sliderPoint.timeout = setTimeout(function() {
							canvas.layerOpacity(layer.spot, layer.opacity);
						}, 100);
					} else if(v.dragdone==false) {
						tempPos += v.dX;
						sliderPoint.pos = tempPos;
						updateOpacity();
						clearTimeout(sliderPoint.timeout);
						sliderPoint.timeout = setTimeout(function() {
							canvas.layerOpacity(layer.spot, layer.opacity);
						}, 100);
					}
					if(v.dragdone===true) {
						clearTimeout(sliderPoint.timeout);
						canvas.layerOpacity(layer.spot, layer.opacity);
						
					}
				});
			}
			
			container1.appendChild(layer.thumb);
			container1.appendChild(layer.label);
			container1.appendChild(layer.opacityLabel);
			container1.appendChild(sliderLine);
			container2.appendChild(sliderPoint);
			
			function dragEventHandler(v) {
				if(v.down) {
					BV.css(layer, {
						transition: ""
					});
					dragContainer.appendChild(layer);
					lastpos = layer.posY;
					div.activateLayer(layer.spot);
					
				} else if(v.dragdone==false) {
					layer.posY += v.dY;
					var corrected = Math.max(0, Math.min((clayers.length-1)*(35),layer.posY));
					layer.style.top =  corrected + "px";
					updateLayers(layer.spot, posToSpot(layer.posY));
					
				}
				if(v.dragdone === true) {
					BV.css(layer, {
						transition: "all 0.1s linear"
					});
					layer.posY = Math.max(0, Math.min((clayers.length-1)*(35),layer.posY));
					regularContainer.appendChild(layer);
					move(layer.spot, posToSpot(layer.posY));
					updatefunc(selected);
					//layer.style.backgroundColor= "rgb( 128, 128,128)";
				}
				return false;
			};
			
			BV.attachMouseListener(container1, dragEventHandler);
			
			regularContainer.appendChild(layer);
		};
		layers = [];
		while(regularContainer.firstChild)
			regularContainer.removeChild(regularContainer.firstChild);
		for(var i = 0; i < clayers.length; i++) {
			createLayerEntry(i);
		}
		div.activateLayer(selected);
	}
	
	
	listdiv.appendChild(regularContainer);
	listdiv.appendChild(dragContainer);
	div.appendChild(listdiv);
	
	
	function posToSpot(p) {
		var result = parseInt((p) /(layerHeight+layerSpacing)+0.5);
		result = Math.min(clayers.length-1, Math.max(0, result));
		result = clayers.length-result-1;
		return result;
	}
	var lastpos = 0;
	function updateLayers(id, newspot) {
		newspot = Math.min(clayers.length-1, Math.max(0, newspot));
		if(newspot != lastpos) {
			for(var i = 0; i < clayers.length; i++) {
				if(layers[i].spot == id)
					continue;
				var posy = layers[i].spot;
				if(layers[i].spot > id)
					posy--;
				if(posy >= newspot)
					posy++;
				layers[i].posY = (layerHeight+layerSpacing)*(clayers.length-posy-1);
				layers[i].style.top = layers[i].posY + "px";
			}
			lastpos = newspot;
		}
	};
	function move(id, newspot) {

		for(var i = 0; i < clayers.length; i++) {
			function loopShit(i) {
				var posy = layers[i].spot;
				if(layers[i].spot == id){
					posy = newspot;
				} else {
					if(layers[i].spot > id)
						posy--;
					if(posy >= newspot)
						posy++;
				}	
				layers[i].spot = posy;
				layers[i].posY = (layerHeight+layerSpacing)*(clayers.length-posy-1);
				layers[i].style.top = layers[i].posY + "px";
			}
			loopShit(i);
		}
		canvas.moveLayer(selected, newspot-id);
		clayers = canvas.getLayers();
		selected = newspot;
		
	}
	
	div.update = function() {
		clayers = canvas.getLayers();
		createLayerList();
	};
	div.updateThumb = function() {
		//updateThumbs();
		if(div.style.display != "block")
			return;
		for(var i = 0; i < layers.length; i++) {
			if(selected == layers[i].spot){
				function stuff(i) {
					var thc = layers[i].thumb.getContext("2d");
					thc.drawImage(clayers[layers[i].spot].context.canvas, 0, 0, layers[i].thumb.width, layers[i].thumb.height);
				}
				stuff(i);
			}
		}
	};
	div.setCanvas = function(c) {
		canvas = c;
		clayers = canvas.getLayers();
		createLayerList();
	}
	div.getSelected = function() {
		return selected;
	}
	div.activateLayer = function(p_i) {
		selected = Math.max(0, Math.min(p_i, layers.length-1));
		for(var i = 0; i < layers.length; i++) {
			if(selected == layers[i].spot) {
				layers[i].style.backgroundColor = "rgb( 250, 250, 250)";
				layers[i].label.style.color = "#000";
				layers[i].label.style.fontWeight = "bold";
			} else {
				layers[i].style.backgroundColor = "rgb( 220, 220, 220)";
				layers[i].label.style.color = "#666";
				layers[i].label.style.fontWeight = "";
			}
		}
	}
	
	createLayerList();
	
	return div;
}

BV.pcWorkspace = function( p_canvas, p_w, p_h, p_func) {
	var div = document.createElement("div");
	div.oncontextmenu = function() { return false };
	var canvas = p_canvas;
	var width = p_w;
	var height = p_h;
	var canvasX = 0, canvasY = 0;
	var zoom = 1;
	div.showPreviewCursor = false;
	//criteras that decide whether or not to show the cursor
	var hover = false, tooSmall = false, paintMode = false, painting = false;
	var cursorPos = {x:0, y:0};
	var showGrid = false;
	
	var brushCursor = document.createElement("div");
	brushCursor.style.display = "block";
	brushCursor.style.position = "absolute";
	var brushsize = 20;
	brushCursor.style.display = "none";
	var paper = Raphael(brushCursor, 8000, 8000);
	var c = paper.circle(brushsize, brushsize, brushsize-1);
	c.attr("stroke", "#000");
	var c2 = paper.circle(brushsize, brushsize, brushsize-2);
	c2.attr("stroke", "#fff");
	
	var previewCursor = document.createElement("div");
	BV.css(previewCursor, {
		position: "absolute",
		display: "none",
		transition: "all 0.6s ease-in-out"
	});
	var prevpaper = Raphael(previewCursor, 8000, 8000);
	var prevc = prevpaper.circle(brushsize, brushsize, brushsize-1);
	prevc.attr("stroke", "#000");
	var prevc2 = prevpaper.circle(brushsize, brushsize, brushsize-2);
	prevc2.attr("stroke", "#fff");
	var previewOpacity = 0;
	
	var previewTimeout;
	
	var gridPaperDiv = document.createElement("div");
	var gridPaper = Raphael(gridPaperDiv, 8000, 8000);
	var gridLines = [];
	gridLines[0] = gridPaper.rect(0, 0, 1, 2000);
	gridLines[1] = gridPaper.rect(0, 0, 2000, 1);
	gridLines[0].attr("stroke", "rgba(0,0,0,0)");
	gridLines[0].attr("fill", "rgba(0,0,0,1)");
	gridLines[1].attr("stroke", "rgba(0,0,0,0)");
	gridLines[1].attr("fill", "rgba(0,0,0,1)");
	BV.css(gridPaperDiv, {
		position: "absolute",
		left: 0,
		top: 0,
		display: "none"
	});
	
	function updateGrid() {
		gridLines[0].attr("x", cursorPos.x);
		gridLines[1].attr("y", cursorPos.y);
	}
	
	brushCursor.onmousemove = function() {
		return false;
	}
	
	
	function decideCursorDisplay() {
		if(hover && !tooSmall && paintMode && !painting) {
			brushCursor.style.display = "block";
			clearTimeout(previewTimeout);
			previewCursor.style.display = "none";
		} else {
			brushCursor.style.display = "none";
		}
	}
	function redrawCursor() {
		c.attr("stroke-width", 1);
		c.attr("cx", brushsize*zoom+100);
		c.attr("cy", brushsize*zoom+100);
		c.attr("r", (brushsize)*zoom);
		c2.attr("stroke-width", 1);
		c2.attr("cx", brushsize*zoom+100);
		c2.attr("cy", brushsize*zoom+100);
		if(brushsize*zoom-1 > 0)
			c2.attr("r", brushsize*zoom-1);
		
		prevc.attr("stroke-width", 1);
		prevc.attr("cx", 4000);
		prevc.attr("cy", 4000);
		prevc.attr("r", (brushsize)*zoom);
		prevc2.attr("stroke-width", 1);
		prevc2.attr("cx", 4000);
		prevc2.attr("cy", 4000);
		if(brushsize*zoom-1 > 0)
			prevc2.attr("r", brushsize*zoom-1);
		
		if(brushsize-1/zoom < 1) {
			tooSmall = true;
		} else {
			tooSmall = false;
		}
		
		decideCursorDisplay();
	}
	div.showDropInfo = function(b) {
		if(b){
			eventdiv.style.backgroundColor = "rgba(0,0,0,0.7)";
			eventdiv.innerHTML = "Drop Image to Import";
		} else{
			eventdiv.style.backgroundColor = "";
			eventdiv.innerHTML = "";
		}
	}
	div.setPaintMode = function(b) {
		if(b) {
			paintMode = true;
		} else {
			paintMode = false;
		}
		
		decideCursorDisplay();
	}
	div.setPainting = function(b) {
		if(b) {
			painting = true;
		} else {
			painting = false;
		}
		decideCursorDisplay();
	}
	div.setCursorSize = function(s) {
		clearTimeout(previewTimeout);
		s = parseInt(s);
		brushsize = s;
		redrawCursor();
		if(!div.showPreviewCursor) {
			return;
		}
		if(tooSmall) {
			previewCursor.style.display = "none";
		} else {
			previewCursor.style.left = (width/2-4000)+"px";
			previewCursor.style.top = (height/2-4000)+"px";
			previewOpacity = 1.0;

			previewCursor.style.opacity = 1.0;
			previewCursor.style.display = "block";
			previewTimeout = setTimeout(function() {
				previewCursor.style.opacity = 0.0;
			}, 600);
		}
	};

	div.setCursorSize(20);
	var eventdiv = document.createElement("div");
	eventdiv.style.width = "100%";
	eventdiv.style.height = "100%";
	eventdiv.style.position = "absolute";
	eventdiv.style.left = "0px";
	eventdiv.style.top = "0px";
	eventdiv.style.color = "#fff";
	eventdiv.style.textAlign = "center";
	eventdiv.style.fontSize = "25px";
	eventdiv.style.fontWeight = "bold";
	eventdiv.style.paddingTop = "100px";
	eventdiv.style.textShadow = "2px 2px 4px rgba(0,0,0,0.5)";
	
	var wrapper = document.createElement("div");
	wrapper.className = "canvasWrapper";
	div.appendChild(wrapper);
	div.appendChild(brushCursor);
	div.appendChild(previewCursor);
	div.appendChild(gridPaperDiv);
	div.appendChild(eventdiv);
	wrapper.appendChild(canvas);
	
	BV.css(div, {
		width: width+"px",
		height: height+"px",
		overflow: "hidden",
		backgroundColor: "#aaa",
		position: "relative"
	});
	BV.css(wrapper, {
		width: "100%",
		height: "100%",
		position: "relative",
		imageRendering: "optimizeSpeed",

		 imageRendering: "-moz-crisp-edges"//,
		 //imageRendering: "-webkit-optimize-contrast"
		// imageRendering: "optimize-contrast",
		 //msInterpolationMode: "nearest-neighbor"*/
	});
	BV.css(canvas, {
		position: "absolute",
		left: 100+"px",
		top: 100+"px"
	});
	
	function center() {
		canvasX = width/2-canvas.width/2;
		canvasY = height/2-canvas.height/2;
		canvas.style.left = canvasX+"px";
		canvas.style.top = canvasY+"px";
	};
	center();
	
	BV.attachMouseListener(div, function(val) {
		if (val.delta && eventdiv.innerHTML == "") {
			if(val.delta < 0) {
				if(div.zoom(div.getZoom()/2))
					val.didZoom = true;
			}
			else {
				if(div.zoom(div.getZoom()*2))
					val.didZoom = true;;
			}
		}
		cursorPos.x = val.absX;
		cursorPos.y = val.absY;
		brushCursor.style.left = parseInt(val.absX-brushsize*zoom-100)+"px";
		brushCursor.style.top = parseInt(val.absY-brushsize*zoom-100)+"px";
		val.cX = (val.absX - width / 2) / zoom - (canvas.offsetLeft - width / 2);
		val.cY = (val.absY - height / 2) / zoom - (canvas.offsetTop - height / 2);
		if(val.over) {
			hover = true;
			decideCursorDisplay();
		} else if(val.out) {
			hover = false;
			decideCursorDisplay();
		} else {
			if(!hover) {
				hover = true;
				decideCursorDisplay();
			}
		}
		
		if(showGrid) {
			updateGrid();
		}
		
		p_func(val);
	});
	
	div.resize = function(p_w, p_h) {
		width = p_w;
		height = p_h;
		BV.css(div, {
			width: width+"px",
			height: height+"px"
		});
		center();
	};
	div.zoom = function(p_z) {
		var oldzoom = zoom;
		zoom = Math.max(0.125, Math.min(16, p_z));
		wrapper.style.MozTransform = "scale("+zoom+")";
		wrapper.style.WebkitTransform = "scale("+zoom+")";
		wrapper.style.OTransform = "scale("+zoom+")";
		wrapper.style.msTransform = "scale("+zoom+")";
		redrawCursor();
		if(zoom != oldzoom) {
			BV.out(parseInt(div.getZoom()*100) + " %");
			return true;
		}
		return false;
	};
	div.move = function(p_x, p_y) {
		canvasX += p_x / zoom;
		canvasY += p_y / zoom;
		BV.css(canvas, {
			left: canvasX+"px",
			top: canvasY+"px"
		});
	}
	div.getZoom = function() {
		return zoom;
	};
	div.setCanvas = function(c) {
		wrapper.removeChild(canvas);
		canvas = c;
		wrapper.appendChild(canvas);
		center();
	};
	div.center = function() {
		center();
	}
	div.showGrid = function(b) {
		var newval = (b) ? true : false;
		if(newval == showGrid) {
			return;
		}
		showGrid = newval;
		if(showGrid) {
			gridPaperDiv.style.display = "block";
			updateGrid();
		} else {
			gridPaperDiv.style.display = "none";
		}
		
	};
	return div;
};

//a simple canvas where you can transform one layer(move around, scale maybe)
BV.FreeTransformCanvas = function(params) {
	var div = document.createElement("div");
	var maxw = 280, maxh = 220;
	var width = 280, height = 220;
	var factor = 1;
	var realWidth = 260, realHeight = 260;
	var x = 0, y = 0; //pos of active
	var hover = false;
	var transform;
	
	var front, active, back; //front - layers in front, active - the active layer, back - layers behind active
	
	if(params.width) {
		width = Math.min(8000, Math.max(1, params.width));
	}
	if(params.height) {
		height = Math.min(8000, Math.max(1, params.width));
	}
	
	// ------------ div structure ----------  //
	
	var previewWrapper = div;
	previewWrapper.style.width = "300px";
	previewWrapper.style.height = "280px";
	previewWrapper.style.display = "table";
	previewWrapper.style.backgroundColor = "#aaa";
	previewWrapper.style.boxShadow = "inset 2px 2px 10px rgba(0,0,0,0.2)";
	previewWrapper.style.overflow = "hidden";

	var previewcell = document.createElement("div");
	previewcell.style.display = "table-cell";
	previewcell.style.verticalAlign = "middle";
	var canvasWrapper = document.createElement("div");
	var layersContainer = BV.appendTextDiv(previewcell, "");
	//canvasWrapper.appendChild(tempCanvas);
	previewWrapper.appendChild(previewcell);
	layersContainer.style.width = width+"px";
	layersContainer.style.height = height+"px";
	layersContainer.style.marginLeft = "auto";
	layersContainer.style.marginRight = "auto";
	layersContainer.style.position = "relative";
	layersContainer.style.boxShadow = "0 0 5px rgba(0,0,0,0.8)";
	layersContainer.style.background = "url(" + BV.createChecker(4) + ")";
	
	
	canvasWrapper.style.position = "absolute";
	canvasWrapper.style.left = "0px";
	canvasWrapper.style.top = "0px";
	canvasWrapper.style.width = width+"px";
	canvasWrapper.style.height = height+"px";
	canvasWrapper.style.overflow = "hidden";
	
	div.setLayers = function(params) {
		return;
	}
	div.setSize = function(params) {
		realWidth = params.width;
		realHeight = params.height;
		var fit = BV.fitInto(maxw, maxh, realWidth, realHeight);
		width = fit.width;
		height = fit.height;
		factor = width / realWidth;
		layersContainer.style.width = width+"px";
		layersContainer.style.height = height+"px";
		canvasWrapper.style.width = width+"px";
		canvasWrapper.style.height = height+"px";
	}
	div.setBackLayer = function(im) {
		back = im;
		BV.css(back, {
			position: "absolute",
			left: "0 px",
			top: "0 px",
			pointerEvents: "none"
		});
		//BV.clearDiv(mask);
		layersContainer.appendChild(back);
		//mask.appendChild(active);
	};
	div.setActiveLayer = function(im) {
		var fit = BV.fitInto(width, height, im.width, im.height);
		if(im.width < realWidth && im.height < realHeight) {
			fit.width = im.width*factor;
			fit.height = im.height*factor;
		}
		active = BV.createCanvas();
		active.width = fit.width;
		active.height = fit.height;
		active.getContext("2d").drawImage(im, 0, 0, active.width, active.height);
		
		transform = new BV.FreeTransform({
			x: fit.width/2,
			y: fit.height/2,
			width: fit.width,
			height: fit.height,
			angle: 0,
			elem: active,
			appendElem: false,
			constrained: true,
			snapX: [0, width],
			snapY: [0, height]
		});
		
		canvasWrapper.appendChild(active);
		layersContainer.appendChild(canvasWrapper);
		layersContainer.appendChild(transform.div);
	};
	div.getFactor = function() {
		return factor;
	}
	//gives you the transformation in the original scale
	div.getTransformation = function() {
		if(!transform)
			return false;
			
		var trans = transform.getTransform();
		trans.width /= factor;
		trans.height /= factor;
		trans.x /= factor;
		trans.y /= factor;
		return trans;
	}
	
	
	return div;
};
/*
BV.previewCanvas = function(params) {
	var canvas = params.canvas; // pcCanvas
	var layer = params.layer; // layer nr
	var callback = params.callback; //callback with information for the middle(zoom, pos) to redraw properly
	var containerWidth = params.containerWidth; //size of the displayed div
	var containerHeight = params.containerHeight;
	var activeLayer = params.activeLayer; //the layer that is being changed by a filter

	var div = document.createElement("div");
	
	
	var back = BV.createCanvas();
	back.width = containerWidth;
	back.height = containerHeigt;
	var middle = BV.createCanvas();
	middle.width = containerWidth;
	middle.height = containerHeigt;
	var front = BV.createCanvas();
	front.width = containerWidth;
	front.height = containerHeigt;
	var custom = document.createElement("div");
	
	function layerStyle(el) {
		el.style.position = "absolute";
		el.style.left = "0px";
		el.style.top = "0px";
		div.appendChild(el);
	}
	layerStyle(back);
	layerStyle(middle);
	layerStyle(fron);
	layerStyle(custom);
	
	var backOriginal, middleOriginal, frontOriginal;
	
	//navi
	var x = 0, y = 0, zoom = 1;
	
	BV.css(div, {
		width: containerWidth+"px",
		height: containerHeight+"px",
		display: "table",
		backgroundImage: "url("+BV.createChecker(Math.max(1,parseInt((8*zoom))))+")",
		boxStyle: "inset 2px 2px 10px #666",
		overflow: "hidden"
	});
	var wrapper = BV.appendTextDiv(div, "");
	BV.css(div, {
		display: "table",
		verticalAlign: "middle",
		boxStyle: "inset 2px 2px 10px #666"
	});
	
	function redraw() {
		
	}
	
	function doZoom(z) {
		zoom = Math.min(2 ,Math.max(0.125(zoom)));
		div.style.backgroundImage = "url("+BV.createChecker(Math.max(1,parseInt((8*zoom))))+")";
	}
	
	BV.attachMouseListener(div, function(v) {
		if (v.delta)
		{
			if(v.delta < 0)
			{
				doZoom(zoom/2);
			}
			else
			{
				doZoom(zoom*2);
			}
		}
		if(v.dX || v.dY) {
			x += v.dX;
			y += v.dY;
		}
		if(v.dragdone)
			redraw();
		div.style.backgroundPosition = x + "px " + y + "px";
	});
	
	div.setCanvas = function(c) {
		canvas = c;
	}
	div.setMiddle = function(c) {
		middleOriginal = c;
	}

	return div;
};*/

/*
	FREETRANSFORM
	params = {
		elem: div,
		x: 100,
		y: 100,
		width: 100,
		height: 100,
		angle: 45, //deg
		constrained: false //constrained porportions
		range: {x:0,y:0,width:200,height:200} ...within what allow pos
		allowRotate: false
		//center
	}

aufbau:
div {
	transdiv [
		elem{}
		outline{}
		edges[]{}
		grips[]{}
		rot{}
		snapX [] //snapping on x axis
		snapY []
		constrained bool
		appendElem bool //put elem into the freetransform div
		callback function(){} //gets called when something was transformed
	}
}

*/
BV.FreeTransform = function(params) {
	var elem = params.elem;
	var x = params.x;
	var y = params.y;
	var width = params.width;
	var height = params.height;
	var angle = params.angle;
	var constrained = params.constrained;
	var appendElem = params.appendElem;
	var snapX = params.snapX;
	var snapY = params.snapY;
	var callback = params.callback;
	var scale = params.scale;
	var snappingEnabled = true;
	var gripCursors = ['nw', 'n','ne','e','se',	's','sw','w'];
	var gripCursorsInverted = ['ne', 'n','nw','w','sw',	's','se','e'];
	var ratio = width/height;
	var mindist = 7; //minimal snapping distance
	
	this.div = document.createElement("div");
	var maindiv = this.div;
	var transdiv = document.createElement("div");
	this.div.appendChild(transdiv);
	var div = transdiv;
	div.style.position = "absolute";
	
	if(appendElem) {
		BV.css(elem, {
			width: "1px",
			height: "1px",
			transformOrigin: "0 0",
			position: "absolute"
		});
	}
	
	
	var outline = document.createElement("div");
	BV.css(outline, {
		position: "absolute",
		cursor: "move",
		border: "1px solid #000"
	});

	BV.attachMouseListener(outline, function(e) {
		if(e.down === true) {
			outline.startPos = {x: x, y: y };
			outline.startMouse = {x: e.absX, y: e.absY };
		}
		if(e.dragdone === false) {
			x = outline.startPos.x + e.absX - outline.startMouse.x;
			y = outline.startPos.y + e.absY - outline.startMouse.y;
			var dist;
			var snap = {};
			if(snappingEnabled) {
				for(var i = 0; i < snapX.length; i++) {
					dist = Math.abs(x - snapX[i]);
					if(dist < mindist) {
						if(!snap.x || dist < snap.distX) {
							snap.x = snapX[i];
							snap.distX = dist;
						}
					}
				}
				for(i = 0; i < snapY.length; i++) {
					dist = Math.abs(y - snapY[i]);
					if(dist < mindist) {
						if(!snap.y || dist < snap.distY) {
							snap.y = snapY[i];
							snap.distY = dist;
						}
					}
				}
			
				var outer;
				for(i = 0; i < 4; i++) {
					outer = getOuter(grips[i].x, grips[i].y);
					for(var j = 0; j < snapX.length; j++) {
						dist = Math.abs(outer.x - snapX[j]);
						if(dist < mindist) {
							if(!snap.x || dist < snap.distX) {
								snap.x = snapX[j] - (outer.x-x);
								snap.distX = dist;
							}
						}
					}
					for(j = 0; j < snapY.length; j++) {
						dist = Math.abs(outer.y - snapY[j]);
						if(dist < mindist) {
							if(!snap.y || dist < snap.distY) {
								snap.y = snapY[j] - (outer.y-y);
								snap.distY = dist;
							}
						}
					}
				}
			}
			if(e.event.shiftKey){
				var projected = BV.projectPointOnLine(
										{x:0, y:outline.startPos.y},
										{x:10,y:outline.startPos.y},
										{x:x, y:y});
				var dist = BV.dist(projected.x,projected.y,x,y);
				snap = {};
				snap.x = projected.x;
				snap.y = projected.y;
				snap.distX = dist;
				snap.distY = dist;
				
				projected = BV.projectPointOnLine(
										{x: outline.startPos.x, y: 0},
										{x: outline.startPos.x, y: 10},
										{x: x, y: y});
				dist = BV.dist(projected.x,projected.y,x,y);
				if(dist < snap.distX) {
					snap.x = projected.x;
					snap.y = projected.y;
					snap.distX = dist;
					snap.distY = dist;
				}
				
				projected = BV.projectPointOnLine(
										{x: outline.startPos.x, y: outline.startPos.y},
										{x: outline.startPos.x+1, y: outline.startPos.y+1},
										{x: x, y: y});
				dist = BV.dist(projected.x,projected.y,x,y);
				if(dist < snap.distX) {
					snap.x = projected.x;
					snap.y = projected.y;
					snap.distX = dist;
					snap.distY = dist;
				}
				
				projected = BV.projectPointOnLine(
										{x: outline.startPos.x, y: outline.startPos.y},
										{x: outline.startPos.x+1, y: outline.startPos.y-1},
										{x: x, y: y});
				dist = BV.dist(projected.x,projected.y,x,y);
				if(dist < snap.distX) {
					snap.x = projected.x;
					snap.y = projected.y;
					snap.distX = dist;
					snap.distY = dist;
				}
			}
			if(snap.x != undefined) {
				x = snap.x;
			}
			if(snap.y != undefined) {
				y = snap.y;
			}
			update();
		}
	});
	
	function checkSnapping(px, py) {
		if(!snappingEnabled) {
			return {x: px, y: py};
		};
		var outer = getOuter(px, py);
		var snap = {};
		for(var e = 0; e < snapX.length; e++) {
			dist = Math.abs(outer.x - snapX[e]);
			if(dist < mindist) {
				if(!snap.x || dist < snap.distX) {
					snap.x = snapX[e];
					snap.distX = dist;
				}
			}
		}
		for(e = 0; e < snapY.length; e++) {
			dist = Math.abs(outer.y - snapY[e]);
			if(dist < mindist) {
				if(!snap.y || dist < snap.distY) {
					snap.y = snapY[e];
					snap.distY = dist;
				}
			}
		}
		if(snap.x != undefined) {
			outer.x = snap.x;
		}
		if(snap.y != undefined) {
			outer.y = snap.y;
		}
		return getInner(outer.x, outer.y);
	}
	
	function constrainedGripPos(i, nx ,ny) {
		if(!constrained) {
			return {
				x: nx,
				y: ny
			};
		}
		var pa = grips[3], pb = grips[1];
		if(i === 0 || i === 2) {
			pa = grips[2];
			pb = grips[0];
		}
		var projected = BV.projectPointOnLine(pa, pb, {x:nx, y:ny});
		
		return {
			x: projected.x,
			y: projected.y
		};
	}
	
	var grips = [];
	for(var i = 0; i < 4; i++) {
		(function(i) {
			grips[i] = document.createElement("div");
			var g = grips[i];
			BV.css(g, {
				width: "10px",
				height: "10px",
				background: "#fff",
				borderRadius: "5px",
				position: "absolute",
				border: "1px solid #000"
			});
			
			g.update = function() {
				var angleOffset = Math.round(angle/45);
				while(angleOffset < 0)
					angleOffset += 8;
				angleOffset = (i*2+angleOffset)%gripCursors.length;
				BV.css(g, {
					left: (g.x-5)+"px",
					top: (g.y-5)+"px"
				});
				if((width < 0 && height >= 0) || (width >= 0 && height < 0)) {
					BV.css(g, {
						cursor: gripCursorsInverted[angleOffset] + "-resize"
					});
				} else {
					BV.css(g, {
						cursor: gripCursors[angleOffset] + "-resize"
					});
				}
			};
		})(i);
	}
	grips[0].x = (-width/2);
	grips[0].y = (-height/2);
	grips[1].x = (width/2);
	grips[1].y = (-height/2);
	grips[2].x = (width/2);
	grips[2].y = (height/2);
	grips[3].x = (-width/2);
	grips[3].y = (height/2);
	
	BV.attachMouseListener(grips[0], function(e) {
		if(e.down === true) 	{
			grips[0].virtualPos = {
				x: grips[0].x,
				y: grips[0].y
			};
		} else if(e.dragdone === false) {
			var inner = BV.rotateAround({x: 0, y:0},
			{x: e.dX, y:e.dY},
			-angle);
			
			grips[0].virtualPos.x += inner.x;
			grips[0].virtualPos.y += inner.y;
			var newPos = constrainedGripPos(0, grips[0].x + inner.x, grips[0].y + inner.y);
			if(!constrained) {
				newPos = checkSnapping(grips[0].virtualPos.x, grips[0].virtualPos.y);
			}
			grips[0].x = newPos.x;
			grips[0].y = newPos.y;
			grips[3].x = grips[0].x;
			grips[1].y = grips[0].y;
			
			grips[0].virtualPos.x -= grips[0].x*0.5 + grips[1].x*0.5;
			grips[0].virtualPos.y -= grips[0].y*0.5 + grips[3].y*0.5;
			commitTransform();
			
		}
	});
	BV.attachMouseListener(grips[1], function(e) {
		if(e.down === true) 	{
			grips[1].virtualPos = {
				x: grips[1].x,
				y: grips[1].y
			};
		} else if(e.dragdone === false) {
			var inner = BV.rotateAround({x: 0, y:0},
			{x: e.dX, y:e.dY},
			-angle);
			
			grips[1].virtualPos.x += inner.x;
			grips[1].virtualPos.y += inner.y;
			var newPos = constrainedGripPos(1, grips[1].x + inner.x, grips[1].y + inner.y);
			if(!constrained) {
				newPos = checkSnapping(grips[1].virtualPos.x, grips[1].virtualPos.y);
			}
			grips[1].x = newPos.x;
			grips[1].y = newPos.y;
			grips[2].x = grips[1].x;
			grips[0].y = grips[1].y;
			grips[1].virtualPos.x -= grips[0].x*0.5 + grips[1].x*0.5;
			grips[1].virtualPos.y -= grips[0].y*0.5 + grips[3].y*0.5;
			commitTransform();
		}
	});
	BV.attachMouseListener(grips[2], function(e) {
		if(e.down === true) 	{
			grips[2].virtualPos = {
				x: grips[2].x,
				y: grips[2].y
			};
		} else if(e.dragdone === false) {
			var inner = BV.rotateAround({x: 0, y:0},
			{x: e.dX, y:e.dY},
			-angle);
			
			grips[2].virtualPos.x += inner.x;
			grips[2].virtualPos.y += inner.y;
			var newPos = constrainedGripPos(2, grips[2].x + inner.x, grips[2].y + inner.y);
			if(!constrained) {
				newPos = checkSnapping(grips[2].virtualPos.x, grips[2].virtualPos.y);
			}
			grips[2].x = newPos.x;
			grips[2].y = newPos.y;
			grips[1].x = grips[2].x;
			grips[3].y = grips[2].y;
			grips[2].virtualPos.x -= grips[0].x*0.5 + grips[1].x*0.5;
			grips[2].virtualPos.y -= grips[0].y*0.5 + grips[3].y*0.5;
			commitTransform();
		}
	});
	BV.attachMouseListener(grips[3], function(e) {
		if(e.down === true) 	{
			grips[3].virtualPos = {
				x: grips[3].x,
				y: grips[3].y
			};
		} else if(e.dragdone === false) {
			var inner = BV.rotateAround({x: 0, y:0},
			{x: e.dX, y:e.dY},
			-angle);
			
			grips[3].virtualPos.x += inner.x;
			grips[3].virtualPos.y += inner.y;
			var newPos = constrainedGripPos(3, grips[3].x + inner.x, grips[3].y + inner.y);
			if(!constrained) {
				newPos = checkSnapping(grips[3].virtualPos.x, grips[3].virtualPos.y);
			}
			grips[3].x = newPos.x;
			grips[3].y = newPos.y;
			grips[0].x = grips[3].x;
			grips[2].y = grips[3].y;
			grips[3].virtualPos.x -= grips[0].x*0.5 + grips[1].x*0.5;
			grips[3].virtualPos.y -= grips[0].y*0.5 + grips[3].y*0.5;
			commitTransform();
		}
	});
	
	var edges = [];
	for(var i = 0; i < 4; i++) {
		(function(i) {
			edges[i] = document.createElement("div");
			var g = edges[i];
			g.style.width = "10px";
			g.style.height = "10px";
			//g.style.background = "#0f0";
			g.style.position = "absolute";
			g.update = function() {
				if(i === 0) {
					g.style.left = Math.min(grips[0].x, grips[1].x)+"px";
					g.style.top = Math.min(grips[0].y, grips[3].y)+"px";
					g.style.width = Math.abs(width)+"px";
					g.style.height = "10px";
					//g.style.background = "#f00";
				} else if(i === 1) {
					g.style.left = (Math.max(grips[0].x, grips[1].x)-10)+"px";
					g.style.top = Math.min(grips[1].y, grips[2].y)+"px";
					g.style.width = "10px";
					g.style.height = Math.abs(height)+"px";
					//g.style.background = "#0f0";
				} else if(i === 2) {
					g.style.left = Math.min(grips[3].x, grips[2].x)+"px";
					g.style.top = (Math.max(grips[0].y, grips[3].y)-10)+"px";
					g.style.width = Math.abs(width)+"px";
					g.style.height = "10px";
					//g.style.background = "#00f";
				} else if(i === 3) {
					g.style.left = Math.min(grips[0].x, grips[1].x)+"px";
					g.style.top = Math.min(grips[0].y, grips[3].y)+"px";
					g.style.width = "10px";
					g.style.height = Math.abs(height)+"px";
					//g.style.background = "#a0a";
				}
				var angleOffset = Math.round(angle/45);
				while(angleOffset < 0)
					angleOffset += 8;
				angleOffset = (i*2+1+angleOffset)%gripCursors.length;
				g.style.cursor = gripCursors[angleOffset] + "-resize";
				
			};
		})(i);
	}
	
	function balanceRatio(boolW, boolH) {
		if(!constrained)
			return;
		if(boolH && !boolW) {
			var newHeight = Math.abs(grips[3].y - grips[0].y);
			var newWidth = ratio*newHeight;
			if(grips[1].x - grips[0].x < 0)
				newWidth *= -1;
			grips[0].x = -newWidth/2;
			grips[3].x = -newWidth/2;
			grips[1].x = newWidth/2;
			grips[2].x = newWidth/2;
		}
		if(!boolH && boolW) {
			var newWidth = Math.abs(grips[0].x - grips[1].x);
			var newHeight = newWidth/ratio;
			if(grips[3].y - grips[0].y < 0)
				newHeight *= -1;
			grips[0].y = -newHeight/2;
			grips[1].y = -newHeight/2;
			grips[2].y = newHeight/2;
			grips[3].y = newHeight/2;
		}
	};
	
	BV.attachMouseListener(edges[0], function(e) {
		if(e.down === true) {
			if(grips[0].y < grips[3].y) {
				inverted = false;
			} else {
				inverted = true;
			}
		}
		if(e.dragdone === false) {
			var inner = BV.rotateAround({x: 0, y:0},
			{x: e.dX, y:e.dY},
			-angle);
			if(inverted === false) {
				grips[0].y += inner.y;
				grips[1].y = grips[0].y;
			} else {
				grips[3].y += inner.y;
				grips[2].y = grips[3].y;
			}
			balanceRatio(false, true);
			commitTransform();
		}
	});
	BV.attachMouseListener(edges[1], function(e) {
		if(e.down === true) {
			if(grips[0].x < grips[1].x) {
				inverted = false;
			} else {
				inverted = true;
			}
		}
		if(e.dragdone === false) {
			var inner = BV.rotateAround({x: 0, y:0},
			{x: e.dX, y:e.dY},
			-angle);
			if(inverted === false) {
				grips[1].x += inner.x;
				grips[2].x = grips[1].x;
			} else {
				grips[0].x += inner.x;
				grips[3].x = grips[0].x;
			}
			balanceRatio(true, false);
			commitTransform();
		}
	});
	BV.attachMouseListener(edges[2], function(e) {
		if(e.down === true) {
			if(grips[0].y < grips[3].y) {
				inverted = false;
			} else {
				inverted = true;
			}
		}
		if(e.dragdone === false) {
			var inner = BV.rotateAround({x: 0, y:0},
			{x: e.dX, y:e.dY},
			-angle);
			if(inverted === false) {
				grips[2].y += inner.y;
				grips[3].y = grips[2].y;
			} else {
				grips[0].y += inner.y;
				grips[1].y = grips[0].y;
			}
			balanceRatio(false, true);
			commitTransform();
		}
	});
	BV.attachMouseListener(edges[3], function(e) {
		if(e.down === true) {
			if(grips[0].x < grips[1].x) {
				inverted = false;
			} else {
				inverted = true;
			}
		}
		if(e.dragdone === false) {
			var inner = BV.rotateAround({x: 0, y:0},
			{x: e.dX, y:e.dY},
			-angle);
			if(inverted === false) {
				grips[0].x += inner.x;
				grips[3].x = grips[0].x;
			} else {
				grips[1].x += inner.x;
				grips[2].x = grips[1].x;
			}
			balanceRatio(true, false);
			commitTransform();
		}
	});
	
	var rot = document.createElement("div");
	(function() {
		var g = rot;
		g.snap = false;
		BV.css(g, {
			cursor: "url(cursor_rotate.png) 10 10, move",
			width: "10px",
			height: "10px",
			background: "#0ff",
			borderRadius: "5px",
			position: "absolute",
			border: "1px solid #000"
		});
		
		var line = document.createElement("div");
		BV.css(line, {
			width: "2px",
			height: "13px",
			left: "4px",
			top: "11px",
			background: "#0ff",
			position: "absolute"
		});
		g.appendChild(line);
		
		g.update = function() {
			BV.css(g, {
					left: (g.x-5)+"px",
					top: (g.y-5)+"px"
			});
		};
		BV.attachMouseListener(g, function(e) {
			if(e.dragdone === false) {
				
				var offset = BV.getGlobalOff(maindiv);
				var o = {x: e.pageX-offset.x, y: e.pageY-offset.y};

				var a = BV.angle({x: x, y: y}, o);
				angle = a;
				if(e.event.shiftKey) {
					angle = Math.round(a/360*8)*45;
				}
				update();
					
			}
		});
	})();
	function commitTransform() {
		centerAround(grips[0].x*0.5 + grips[1].x*0.5,
					grips[0].y*0.5 + grips[3].y*0.5);
		
		width = grips[1].x - grips[0].x;
		height = grips[3].y - grips[0].y;
		
		grips[0].x = (-width/2);
		grips[0].y = (-height/2);
		grips[1].x = (width/2);
		grips[1].y = (-height/2);
		grips[2].x = (width/2);
		grips[2].y = (height/2);
		grips[3].x = (-width/2);
		grips[3].y = (height/2);
		
		update();
	};
	
	function getInner(ox, oy) {
		var px, py;
		px = ox - x;
		py = oy - y;
		
		var rot = BV.rotateAround({x: 0, y:0},
			{x: px, y:py},
			-angle);
		px = rot.x;
		py = rot.y;
		
		return {
			x: px,
			y: py
		};
	}
	
	function getOuter(ix, iy) {
		var rot = BV.rotateAround({x: 0, y:0},
			{x: ix, y:iy},
			angle);
		return {
			x: rot.x + x,
			y: rot.y + y
		};
	}
	
	function centerAround(cx, cy) {
		var rot = BV.rotateAround({x: 0, y:0},
			{x: cx, y:cy},
			angle);
		x = rot.x + x;
		y = rot.y + y;
		
		update();
	};
	
	function update(skipcallback) {
		
		BV.css(div, {
			left: x + "px",
			top: y + "px",
			WebkitTransformOrigin: "0 0",
			WebkitTransform: "rotate(" + angle + "deg)",
			MozTransformOrigin: "0 0",
			MozTransform: "rotate(" + angle + "deg)"
		});
		
		if(appendElem) {
			BV.css(elem, {
				WebkitTransform: "scale(" + width + ", " + height + ")",
				MozTransform: "scale(" + width + ", " + height + ")",
				left: (grips[0].x) + "px",
				top: (grips[0].y) + "px"
			});
		} else {
			BV.css(elem, {
				width: "1px",
				height: "1px",
				position: "absolute",
				transformOrigin: "50% 50%",
				transform: "rotate(" + angle + "deg) scale(" + width + ", " + height + ")",
				left: (x) + "px",
				top: (y) + "px"
			});
		}
		
		BV.css(outline, {
			width: Math.abs(width) + "px",
			height: Math.abs(height) + "px",
			left: Math.min(grips[0].x, grips[1].x) + "px",
			top: Math.min(grips[0].y, grips[3].y) + "px"
		});
		
		grips[0].update();
		grips[1].update();
		grips[2].update();
		grips[3].update();
		
		edges[0].update();
		edges[1].update();
		edges[2].update();
		edges[3].update();
		
		
		rot.x = 0;
		rot.y = (-Math.abs(height)/2) - 20;
		rot.update();
		if(!skipcallback) {
			if(callback) {
				callback(getTransform());
			}
		}
	}
	update();
	if(appendElem) {
		div.appendChild(elem);
	}
	div.appendChild(outline);
	div.appendChild(edges[0]);
	div.appendChild(edges[1]);
	div.appendChild(edges[2]);
	div.appendChild(edges[3]);
	div.appendChild(grips[0]);
	div.appendChild(grips[1]);
	div.appendChild(grips[2]);
	div.appendChild(grips[3]);
	div.appendChild(rot);
	
	function getTransform() {
		return {
			x: x,
			y: y,
			width: width,
			height: height,
			angle: angle
		};
	}
	this.getTransform = getTransform;
	this.setConstrained = function(b) {
		if(b) {
			constrained = true;
			ratio = Math.abs(width/height);
		} else {
			constrained = false;
		}
	};
	this.setSnapping = function(s) {
		snappingEnabled = (s) ? true : false;
	};
	this.setPos = function(p) {
		x = p.x+0;
		y = p.y+0;
		update(true);
	};
	this.setAngle = function(a) {
		angle = a;
		update(true);
	};
};

/*
	Cropper params
	{
		x: int, //pos in relation zum bild
		y: int,
		w: int,
		h: int,
		scale: float, //zoom
		callback: function //wenn sich was ändert
	}
	the div that you append this to must be relative
*/
BV.Cropper = function(params) {
	var x = params.x,
		y = params.y,
		width = params.width,
		height = params.height,
		scale = params.scale,
		callback = params.callback,
		maxW = params.maxW,
		maxH = params.maxH;
	var div = document.createElement("div");
	var gripCursors = ['nw', 'n','ne','e','se',	's','sw','w'];
	
	BV.css(div, {
		position: "absolute",
		left: (x * scale) + "px",
		top: (y * scale) + "px"
	});
	
	var outline = document.createElement("div");
	BV.css(outline, {
		position: "absolute",
		border: "1px dashed #fff",
		cursor: "move"
	});
	outline.update = function() {
		BV.css(outline, {
			left: (grips[0].x * scale - 1) + "px",
			top: (grips[0].y * scale - 1) + "px",
			width: ((grips[2].x - grips[0].x) * scale) + "px",
			height: ((grips[2].y - grips[0].y) * scale) + "px"
		});
	};
	BV.attachMouseListener(outline, function(e) {
		if(e.dragdone === false) {
			grips[0].x += e.dX/scale;
			grips[0].y += e.dY/scale;
			grips[1].x += e.dX/scale;
			grips[1].y += e.dY/scale;
			grips[2].x += e.dX/scale;
			grips[2].y += e.dY/scale;
			grips[3].x += e.dX/scale;
			grips[3].y += e.dY/scale;
			
			update();
		}
		if(e.dragdone === true) {
			callback(getTransform());
		}
	});
	
	var thirdsHorizontal = document.createElement("div");
	BV.css(thirdsHorizontal, {
		position: "absolute",
		borderTop: "1px solid #0ff",
		borderBottom: "1px solid #0ff"
	});
	thirdsHorizontal.update = function() {
		BV.css(thirdsHorizontal, {
			left: (grips[0].x * scale) + "px",
			top: ((grips[0].y + (grips[2].y - grips[0].y)/3) * scale) + "px",
			width: ((grips[2].x - grips[0].x) * scale) + "px",
			height: ((grips[2].y - grips[0].y)/3 * scale) + "px"
			
		});
	};
	var thirdsVertical = document.createElement("div");
	BV.css(thirdsVertical, {
		position: "absolute",
		borderLeft: "1px solid #0ff",
		borderRight: "1px solid #0ff"
	});
	thirdsVertical.update = function() {
		BV.css(thirdsVertical, {
			left: ((grips[0].x + (grips[2].x - grips[0].x)/3) * scale) + "px",
			top: (grips[0].y * scale) + "px",
			width: ((grips[2].x - grips[0].x)/3 * scale) + "px",
			height: ((grips[2].y - grips[0].y) * scale) + "px"
			
		});
	};
	
	var grips = [];
	grips[0] = {};
	grips[0].x = 0;
	grips[0].y = 0;
	grips[1] = {};
	grips[1].x = width;
	grips[1].y = 0;
	grips[2] = {};
	grips[2].x = width;
	grips[2].y = height;
	grips[3] = {};
	grips[3].x = 0;
	grips[3].y = height;
	
	var edges = [];
	for(var i = 0; i < 4; i++) {
		(function(i) {
			edges[i] = document.createElement("div");
			var g = edges[i];
			g.style.width = "10px";
			g.style.height = "10px";
			//g.style.background = "#0f0";
			g.style.position = "absolute";
			g.update = function() {
				if(i === 0) {
					g.style.left = (grips[0].x * scale) + "px";
					g.style.top = (grips[0].y * scale - 10) + "px";
					g.style.width = ((grips[1].x - grips[0].x) * scale) + "px";
					g.style.height = "20px";
				} else if(i === 1) {
					g.style.left = (grips[1].x * scale - 10) + "px";
					g.style.top = (grips[1].y * scale) + "px";
					g.style.width = "20px";
					g.style.height = ((grips[2].y - grips[1].y) * scale) + "px";
				} else if(i === 2) {
					g.style.left = (grips[3].x * scale) + "px";
					g.style.top = (grips[3].y * scale - 10) + "px";
					g.style.width = ((grips[2].x - grips[3].x) * scale) + "px";
					g.style.height = "20px";
				} else if(i === 3) {
					g.style.left = (grips[0].x * scale - 10) + "px";
					g.style.top = (grips[0].y * scale) + "px";
					g.style.width = "20px";
					g.style.height = ((grips[3].y - grips[0].y) * scale) + "px";
				}
				var angleOffset = i*2+1;
				g.style.cursor = gripCursors[angleOffset] + "-resize";
				
			};
		})(i);
	}
	
	var darken = [];
	for(var i = 0; i < 4; i++) {
		(function(i) {
			darken[i] = document.createElement("div");
			var g = darken[i];
			g.style.width = "10px";
			g.style.height = "10px";
			g.style.position = "absolute";
			g.style.background = "#000";
			g.style.opacity = "0.5";
			g.update = function() {
				if(i === 0) {
					g.style.left = (grips[0].x * scale) + "px";
					g.style.top = (grips[0].y * scale - 8000) + "px";
					g.style.width = ((grips[1].x - grips[0].x) * scale) + "px";
					g.style.height = "8000px";
				} else if(i === 1) {
					g.style.left = (grips[1].x * scale) + "px";
					g.style.top = (grips[1].y * scale - 8000) + "px";
					g.style.width = "8000px";
					g.style.height = 16000 + "px";
				} else if(i === 2) {
					g.style.left = (grips[3].x * scale) + "px";
					g.style.top = (grips[3].y * scale) + "px";
					g.style.width = ((grips[2].x - grips[3].x) * scale) + "px";
					g.style.height = "8000px";
				} else if(i === 3) {
					g.style.left = (grips[0].x * scale - 8000) + "px";
					g.style.top = (grips[0].y * scale - 8000) + "px";
					g.style.width = "8000px";
					g.style.height = 16000 + "px";
				}
				
			};
		})(i);
	}
	
	BV.attachMouseListener(edges[0], function(e) {
		if(e.dragdone === false) {
			grips[0].y += e.dY/scale;
			grips[0].y = Math.max(grips[3].y - maxH, Math.min(grips[3].y - 1, grips[0].y));
			grips[1].y = grips[0].y;
			
			update();
		}
		if(e.dragdone === true) {
			callback(getTransform());
		}
	});
	BV.attachMouseListener(edges[1], function(e) {
		if(e.dragdone === false) {
			grips[1].x += e.dX/scale;
			grips[1].x = Math.min(grips[0].x + maxW, Math.max(grips[0].x + 1, grips[1].x));
			grips[2].x = grips[1].x;
			
			update();
		}
		if(e.dragdone === true) {
			callback(getTransform());
		}
	});
	BV.attachMouseListener(edges[2], function(e) {
		if(e.dragdone === false) {
			grips[2].y += e.dY/scale;
			grips[2].y = Math.min(grips[1].y + maxH, Math.max(grips[1].y + 1, grips[2].y));
			grips[3].y = grips[2].y;
			
			update();
		}
		if(e.dragdone === true) {
			callback(getTransform());
		}
	});
	BV.attachMouseListener(edges[3], function(e) {
		if(e.dragdone === false) {
			grips[0].x += e.dX/scale;
			grips[0].x = Math.max(grips[1].x - maxW, Math.min(grips[1].x - 1, grips[0].x));
			grips[3].x = grips[0].x;
			
			update();
		}
		if(e.dragdone === true) {
			callback(getTransform());
		}
	});
	
	function getTransform() {
		grips[1].x -= grips[0].x;
		grips[1].y -= grips[0].y;
		grips[2].x -= grips[0].x;
		grips[2].y -= grips[0].y;
		grips[3].x -= grips[0].x;
		grips[3].y -= grips[0].y;
		x += grips[0].x;
		y += grips[0].y;
		grips[0].x = 0;
		grips[0].y = 0;
		return {
			x: x,
			y: y,
			width: grips[1].x,
			height: grips[2].y
		};
	}
	div.getTransform = getTransform;
	div.setTransform = function(p) {
		x = p.x;
		y = p.y;
		width = p.width;
		height = p.height;
		
		BV.css(div, {
			left: (x * scale) + "px",
			top: (y * scale) + "px"
		});
		
		grips[0].x = 0;
		grips[0].y = 0;
		grips[1].x = width;
		grips[1].y = 0;
		grips[2].x = width;
		grips[2].y = height;
		grips[3].x = 0;
		grips[3].y = height;
		
		update();
		callback(getTransform());
	};
	div.setScale = function(s) {
		scale = s;
		BV.css(div, {
			left: (x * scale) + "px",
			top: (y * scale) + "px"
		});
		update();
	};
	
	div.showThirds = function(b) {
		if(b) {
			thirdsHorizontal.style.display = "block";
			thirdsVertical.style.display = "block";
		} else {
			thirdsHorizontal.style.display = "none";
			thirdsVertical.style.display = "none";
		}
	};
	
	div.appendChild(darken[1]);
	div.appendChild(darken[0]);
	div.appendChild(darken[2]);
	div.appendChild(darken[3]);
	div.appendChild(thirdsHorizontal);
	div.appendChild(thirdsVertical);
	div.appendChild(outline);
	
	div.appendChild(edges[1]);
	div.appendChild(edges[0]);
	div.appendChild(edges[2]);
	div.appendChild(edges[3]);
	
	function update() {
		
		edges[0].update();
		edges[1].update();
		edges[2].update();
		edges[3].update();
		darken[0].update();
		darken[1].update();
		darken[2].update();
		darken[3].update();
		outline.update();
		thirdsHorizontal.update();
		thirdsVertical.update();
	}
	update();
	return div;
};
