function MandelBrot(canvas){
	return new MandelBrotClass(canvas);
}

function MandelBrotClass(canvas){
	this.canvas=canvas;
	this.x=0;
	this.y=0;
	this.width=100;
	this.height=100;
	
	this.vxmin=-2;
	this.vxmax=2;

	this.vymin=-2;
	this.vymax=2;
	
	this.zoomActive=false;
	
	
	var c=Canvas();
	
	c.element=document.createElement('canvas');	
	c.element.width=20;
	c.element.height=20;
	if(typeof(G_vmlCanvasManager)!='undefined'){
		G_vmlCanvasManager.initElement(c.element);
	}
	c.init();
	c.fillStyle("#ffffff")
	c.fillRect(0,0,5,5);
	c.fillRect(10,0,5,5);	
	c.fillRect(5,5,5,5);
	c.fillRect(15,5,5,5);	
	c.fillRect(0,10,5,5);
	c.fillRect(10,10,5,5);
	c.fillRect(5,15,5,5);
	c.fillRect(15,15,5,5);	
	
	this.strokePattern=this.canvas.createPattern(c.element,'repeat');	
}


MandelBrotClass.prototype.zoomWheel = function(e){
	if (e.wheelDelta) {
		delta = e.wheelDelta/120; 
		if (window.opera) delta = -delta;
	} else if (e.detail) {
		delta = -e.detail/3;
	}
	var half_width=this.width/2;
	var d=this.vxmax-this.vxmin;
	var d2=d/2;
	var dist_from_middle=((e.layerX-this.x)-half_width)/half_width;
	
	var dist_from_vmiddle=d2*dist_from_middle;
	//moves the vi
	//this.vxmin+=d*((e.layerX-this.x)-half_width)/half_width
	//this.vxmax+=d*((e.layerX-this.x)-half_width)/half_width
	if(delta>0){	
		d2*=0.8;	
		this.vxmin*=0.8
		this.vxmax*=0.8
		this.vymin*=0.8
		this.vymax*=0.8						
	}else{
		d2*=1.2;		
		this.vxmin*=1.2
		this.vxmax*=1.2
		this.vymin*=1.2
		this.vymax*=1.2		
	}
	this.vxmin+=d2*dist_from_middle;
	this.vxmax+=d2*dist_from_middle;
	this.draw();
}

MandelBrotClass.prototype.zoomEnd = function(e){
	var edistance=((e.x-this.x))/this.width;
	var sdistance=((this.startZoom.x-this.x))/this.width;
	var d=this.vxmax-this.vxmin;
	var min=this.vxmin;
	if(edistance<sdistance){
		this.vxmin=d*edistance+min;
		this.vxmax=d*sdistance+min;
	}else{
		this.vxmin=d*sdistance+min;
		this.vxmax=d*edistance+min;	
	}
	var min=this.vymin;	
	var edistance=((e.y-this.y))/this.height;
	var sdistance=((this.startZoom.y-this.y))/this.height;
	var d=this.vymax-this.vymin;
	if(edistance<sdistance){
		this.vymin=d*edistance+min;
		this.vymax=d*sdistance+min;
	}else{
		this.vymin=d*sdistance+min;
		this.vymax=d*edistance+min;	
	}	
	this.zoomActive=false;
	this.draw();
}

MandelBrotClass.prototype.zoomStart = function(coord){
	this.startZoom=coord;
	this.endZoom = coord;
	this.zoomActive=true;
	this.draw();	
}

MandelBrotClass.prototype.zoomSelecting = function(coord){
	
	if (this.zoomActive) {	
		this.endZoom = coord;
		this.draw();
	}
}


MandelBrotClass.prototype.init = function(){
	var me = this;
	this.canvas.listen_mousewheel(this.x, this.y, this.width, this.height, function(e){
		me.zoomWheel(e);
	});
	this.canvas.listen_mousedown(this.x, this.y, this.width, this.height, function(e){
		me.zoomStart(e);
	});
	this.canvas.listen_mouseup(this.x, this.y, this.width, this.height, function(e){
		me.zoomEnd(e);
	});	
	this.canvas.listen_mousemove(this.x, this.y, this.width, this.height, function(e){
		me.zoomSelecting(e);
	});		
		
	this.draw();
}
MandelBrotClass.prototype.draw = function(){
	if(this.zoomActive){
		var x,y,w,h;
		if(this.startZoom.x<=this.endZoom.x){
			x=this.startZoom.x;
			w=this.endZoom.x-this.startZoom.x;
		}else{
			x=this.endZoom.x;
			w=this.startZoom.x-this.endZoom.x;			
		}
		if(this.startZoom.y<=this.endZoom.y){
			y=this.startZoom.y;
			h=this.endZoom.y-this.startZoom.y;
		}else{
			y=this.endZoom.y;
			h=this.startZoom.y-this.endZoom.y;			
		}	
		this.canvas.putImageData(this.pixels,this.x,this.y);
		this.canvas.strokeStyle(this.strokePattern);

		this.canvas.strokeRect(x,y,w,h);
		return true;
	}
	this.pixels = this.canvas.createImageData(this.width, this.height);
	if(this.pixels==false){
		this.canvas.fillText("Browser don't supporte createImageData",this.x,this.y);
		return;
	}
	var xd=(this.vxmax-this.vxmin) / this.width;
	var yd= (this.vymax-this.vymin) / this.height
	var xp=0;
	var ypd=this.width*4;
	var endX=this.width*((this.vxmax-this.vxmin) / this.width);
	var endY=((this.vymax-this.vymin) / this.height)*this.height;
	for (var x0 = 0; x0 <endX; x0+=xd,xp+=4){	
		var yp=0;	
		for (var y0 = 0; y0 <endY; y0+=yd,yp+=ypd){
			//var i=this.escapesToInfinity(this.vxmin + x0  ,this.vymin + y0);	
		    var x = 0.0;
		    var y = 0.0;
		    var i = 0;
			var a=this.vxmin + x0;
			var b=this.vymin + y0;
		    do {
				var xnew = x * x - y * y + a;
				var ynew = 2 * x * y + b;
				x = xnew;
				y = ynew;
				i++;
				if (i == 100){
					i=-1;break;}
			} while (x <= 2 && y <= 2);

								
			var pixelIndex=xp+yp;
		    if (i == -1) {
				this.pixels.data[pixelIndex] = 0;
				this.pixels.data[pixelIndex + 1] = 0;
				this.pixels.data[pixelIndex + 2] = 0;
				this.pixels.data[pixelIndex + 3] =255;
			}
			else {
				if (i < 15) {
					this.pixels.data[pixelIndex] = 0;
					this.pixels.data[pixelIndex + 1] =Math.floor(255 / 15 * i) ;
					this.pixels.data[pixelIndex + 2] = Math.floor(255 / 15 * (15-i));
					this.pixels.data[pixelIndex + 3] = 255;
				}else if (i < 65) {
					this.pixels.data[pixelIndex] = Math.floor(255 / 50 * (i-15));
					this.pixels.data[pixelIndex + 1] = Math.floor(255 / 50 * (50-i-15));
					this.pixels.data[pixelIndex + 2] = 0;
					this.pixels.data[pixelIndex + 3] = 255;
				}
				else {
					this.pixels.data[pixelIndex] = Math.floor(255 / 35 * (35-i-65));
					this.pixels.data[pixelIndex + 1] = Math.floor(255 / 35 * (i-65));
					this.pixels.data[pixelIndex + 2] = 0;
					this.pixels.data[pixelIndex + 3] = 255;
				}
			}
									
		}
	}
	this.canvas.putImageData(this.pixels,this.x,this.y);
}

if(typeof(JCanvasDSLClass)=="function"){
	JCanvasDSLClass.prototype.rootNode.mandelBrot=function(self,node){			
		var ele=MandelBrot(self.canvas,self.canvas);
		self.mapAttributes(node,ele,[
				['x','x',parseInt],
				['y','y',parseInt],
				['width','width',parseInt],
				['height','height',parseInt]							
				]
		);	
		var c=self.firstChild(node);
		ele.init();		
	}
}

