var shaper = function(){
	this.shapes || (this.shapes = {});
	var self = this,
		ieParam = 100;
	
	function set(id, array){
		if(!self.shapes[id] || self.shapes[id].array != array) {
			self.shapes[id] = {
				array: array,
				array_string: convertArray2arrayString(array)
			};
			self.shapes[id].string = convertArrayString2string(shapes[id].array_string);
		}
		
		return getString(id);
	}
	
	function setPoints(id, points){
		for (var i = 0; i < points.length; i++) {
			self.shapes[id].array[points[i].index] = points[i].data;
			self.shapes[id].array_string[points[i].index] = convertArray2point(points[i].data);	
		}
		self.shapes[id].string = convertArrayString2string(shapes[id].array_string);
		return getString(id);
	}
	
	function getString(id){ return shapes[id].string;}
	function getArray(id){ return shapes[id].array; }
	function getPoint(id, index){ return shapes[id].array[index]; }

	function convertArray2arrayString(array){
		var ret = [];
		for(var i=0; i < array.length; ret[i] = convertArray2point(array[i++]));
		return ret;
	}

	function convertArrayString2string(array){
		return array.join(' ');
	}
	
	function convertArray2string(array){
		var ret = '';
		for(var i=0; i < array.length; i++){
			!i || (ret+=' ');
			for(var j=0; j < array.length; array[i][j] = convertArray2point(array[i][j++]));
		}
		return ret;
	}

	function convertArray2point(array){
		var point = array[0]=='z' && $.browser.msie ? 'ex' : array[0];
		for(var i=1; i < array.length; i++){
			point += ' '+ ($.browser.msie
							? parseInt(array[i][0]*ieParam)+','+parseInt(array[i][1]*ieParam)
							: array[i].join(','));
		}
		return point;
	}

	function animateShape(jHover, jPath, sId, aPoints, aPointsBack, isStack, time, easing){
		time || (time = 5000);
		easing || (easing = "linear");
		$(jHover).hover(function(e, stopAfter){
			var counter = 0,
				curtime = stopAfter ? time * 40 : time;
			$(jPath).stop(true);
			
			
			if(stopAfter) {
				window.jHover = jHover;
				window.jHoverTimer = setTimeout("$(window.jHover).trigger('mouseout', ["+(curtime/2)+"])",time);
			} else {
				if(window.jHoverTimer) clearTimeout(window.jHoverTimer);
			}
			
			function queue() {
				if(isStack) {
					counter = counter >= aPoints.length ? 0 : counter;
					$(jPath).animate({
						"path":{
							shaper_id:sId,
							points: aPoints[counter++]
						}
					}, curtime, easing, queue);
					
				} else {
					$(jPath).animate({
						"path":{
							shaper_id:sId,
							points: aPoints
						}
					}, curtime, easing);
				}
			}
			queue();
		}, function(e, curtime){
			curtime = curtime ? curtime : time;
			if(window.jHoverTimer && !curtime) clearTimeout(window.jHoverTimer);
			
			$(jPath).stop(true).animate({
				"path":{
					shaper_id:sId,
					points: aPointsBack
				}
			}, curtime, easing);
		});
	}
	
	function createBlotVml(parent, src, shapes, isFirstRun){
		$(parent).html('');
		var myDiv = document.getElementById("blot");
		
		var path = myDiv.appendChild(document.createElement("v:shape"));
		path.style.position = 'relative';
		path.style.margin = "-2px 0 0 -2px";
		path.style.display = 'block';
		path.style.width = path.style.height = '120px';
		
		path.strokecolor = $("body").hasClass("dark") ? "#ffffff" : "none";
		path.coordsize="12000, 12000";
		path.coordorigin="0, 0";
		path.path = shaper().set("shape", shapes.shape);
		var image = path.appendChild(document.createElement("v:fill"));
		image.type = 'tile';
		image.src = src;
		
		shaper().animateShape($("#blot").parent(), path, "shape", shapes.start, shapes.end, false);
		if(isFirstRun) $($("#blot").parent()).trigger('mouseenter', [true]);
	}

	function createBlotSvg(parent, src, shapes, isFirstRun){
		$(parent).html('');
		$(parent).svg({
			onLoad: function(svg){
			
				var defs = svg.defs('myDefs'),
					ptn = svg.pattern(defs, 'myPat', 0, 0, 120, 120, 0, 0, 0, 0, {
					patternUnits: 'userSpaceOnUse',
					fill: 'red'
				}),
					image = svg.image(ptn, 0, 0, 120, 120, src),
					settings = {
						id: "path",
						fill: "url(#myPat)"
					};
				
				!$("body").hasClass("dark") || (settings.stroke = "#ffffff");
				
				var path = svg.path(null, shaper().set("shape", shapes.shape), settings);
				shaper().animateShape($("#blot").parent(), path, "shape", shapes.start, shapes.end, false);
				if(isFirstRun) $($("#blot").parent()).trigger('mouseenter', [true]);
			},
			settings: {
				width: '120px',
				height: '120px'
			}
		});
	}

	return {
		set:set,
		setPoints:setPoints,
		getString:getString,
		getArray:getArray,
		getPoint:getPoint,
		animateShape:animateShape,
		createBlotVml:createBlotVml,
		createBlotSvg:createBlotSvg
	};
}

$.fx.step['d'] = $.fx.step['path'] = function(fx){
		fx.shape_point || (fx.shape_point = shaper().getArray(fx.end["shaper_id"]));
		fx.posPoints || (fx.posPoints = jQuery.extend(true, [], fx.end["points"]));
		for(var i = 0; i < fx.end["points"].length; i++) {
			for(var j = 1; j < fx.end["points"][i].data.length; j++){
				var shape_point = fx.shape_point[fx.end["points"][i].index][j],
					point = fx.end["points"][i].data[j];
				if(point != shape_point) {
					fx.posPoints[i].data[j] = [
						shape_point[0] + (point[0]-shape_point[0])*fx.pos,
						shape_point[1] + (point[1]-shape_point[1])*fx.pos
					];
						//$("body").append('<div>'+((shape_point[0] + (point[0]-shape_point[0])*fx.pos).toFixed(1))+'</div>');
				}
			}
		}
		$.browser.msie
			? (fx.elem.path = shaper().setPoints(fx.end["shaper_id"], fx.posPoints))
			: $(fx.elem).attr("d", shaper().setPoints(fx.end["shaper_id"], fx.posPoints));
}
