//////////////////////////////////////////////////////////////////
// Wilderness Copyright (c) 2010 Dave Griffiths GPLv3 See COPYING
//////////////////////////////////////////////////////////////////

function vec3(x,y,z)
{
	this.x=x;
    this.y=y;
	this.z=z;
		
	this.add = function(other)
	{
		return new vec3(this.x+other.x,this.y+other.y,this.z+other.z);
	}

	this.sub = function(other)
	{
		return new vec3(this.x-other.x,this.y-other.y,this.z-other.z);
	}
	
	this.mag = function(other)
	{
		return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z);
	}
	
	this.lerp = function(other,t)
	{
		return new vec3(this.x*(1-t) + other.x*t,
						this.y*(1-t) + other.y*t,
						this.z*(1-t) + other.z*t);
	}
}

//////////////////////////////////////////////////////////////

function circle(centre,radius)
{
    this.centre = centre;
    this.radius = radius;
	
	this.inside = function(pos) 
	{
		return pos.sub(this.centre).mag()<this.radius;
	}
}

//////////////////////////////////////////////////////////////

function rnd_gen()
{
	this.state=0;
		
	this.seed = function (s)
	{
		this.state=s;
	}
	
	this.rnd_int = function()
	{
		this.state=10331*this.state+1203432033;
        this.state=this.state%256;
		return this.state;
	}
	
	this.rnd_flt = function()
	{
		return this.rnd_int()/256;
	}
}

/////////////////////////////////////////////////////////////

function entity(pos,image_filename)
{
	this.pos=pos;
    this.sprite = new Image();
    this.sprite.src = image_filename;
    this.screen_x = 0;
    this.screen_y = 0;
    this.scale = 1; // todo replace with matrix
	this.rotate = 0;

	this.change_bitmap = function(image_filename)
	{
        this.sprite.src = image_filename;
	};

	this.set_scale = function(s)
	{
        this.scale=s;
	};
	
	this.set_rotate = function(s)
	{
        this.rotate=s;
	};
	
	this.pos2screenpos = function(pos)
	{
		// do the nasty iso conversion
		// this is actually an orthogonal projection matrix! (I think)
		return new vec3(250+(pos.x*36-pos.y*26),50+(pos.y*18+pos.x*9)-(pos.z*37),0);
	};
	
    this.update_pos = function() 
	{ 
		var pos = this.pos2screenpos(this.pos);
		this.screen_x=pos.x;
		this.screen_y=pos.y;
	};
	
	this.update = function(frame, world)
	{
	};

    this.draw = function(ctx)
    {
        ctx.translate(this.screen_x, this.screen_y);        
        ctx.drawImage(this.sprite,0,0);
    };

    this.update_pos();
}

////////////////////////////////////////////////////////////////

function animated_entity(pos,bitmap_filename)
{
    this.super = entity;
    this.super(pos,bitmap_filename);
	this.src_pos=new vec3(0,0,0);
	this.dest_pos=new vec3(0,0,0);
	this.time=10;
	this.speed=0;
		
	this.move_to = function(pos,speed)
	{
		this.src_pos=pos;
		this.dest_pos=pos;
		this.time=0;
		this.speed=speed;
	};
	
	this.update = function(frame, world)
	{
		//this.super.update(frame,world);
		
		if (this.time<1) 
		{
			this.time+=this.speed;
			if (this.time>1) this.time=1;
			this.pos=this.src_pos.lerp(this.dest_pos,this.time);
			this.update_pos();
		}
	};
}

////////////////////////////////////////////////////////////////

function cube(pos)
{	
	this.super = entity;
    this.super(pos, "blue-cube.png");	
	
	this.update_tex = function(rnd)
	{
		if (this.pos.z<0)
		{ 
			if (rnd.rnd_flt()<0.5)
			{
				this.change_bitmap("sea-cube-01.png");
			}
			else
			{
				if (rnd.rnd_flt()<0.5)
				{
					this.change_bitmap("sea-cube-02.png");
				}
				else
				{
					this.change_bitmap("sea-cube-03.png");
				}
			}
		}
		else 
		{
			if (rnd.rnd_flt()<0.5)
			{
				this.change_bitmap("grass-cube-01.png");
			}
			else
			{
				if (rnd.rnd_flt()<0.5)
				{
					this.change_bitmap("grass-cube-02.png");
				}
				else
				{
					this.change_bitmap("grass-cube-03.png");
				}
			}
		}
	};
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

function plant(owner,pos,bitmap_filename)
{
    this.super = entity;
    this.super(pos,bitmap_filename);
	this.owner=owner;
    this.plant_scale=230;
    this.set_scale(0.1);
	
	this.update = function(frame, world)
	{
		//this.super.update(frame,world);
		if (this.plant_scale>0)
		{
			this.set_scale(1.01);
			this.plant_scale--;
		}
	};
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

function player_entity(pos)
{
    this.super = entity;
    this.super(pos,"bbot-north.png");

	this.handle = function(e, world)
	{
		var pos=new vec3(this.pos.x,this.pos.y,this.pos.z);
        //alert(e.keyCode);
	
		if (e.keyCode==37) { pos.x-=1; this.change_bitmap("bbot-north.png"); }
		if (e.keyCode==39) { pos.x+=1; this.change_bitmap("bbot-south.png"); }
		if (e.keyCode==38) { pos.y-=1; this.change_bitmap("bbot-east.png"); }
		if (e.keyCode==40) { pos.y+=1; this.change_bitmap("bbot-west.png"); }
		if (e.keyCode==32) { world.add_server_plant(new vec3(pos.x,pos.y,1)); }
		
		var oldworldpos=new vec3(world.world_pos.x,world.world_pos.y,world.world_pos.z);

		if (pos.x<0)
		{
			pos.x=world.width-1;
			world.update_world(world.world_pos.add(new vec3(-1,0,0)));
		}

		if (pos.x>=world.width)
		{
			pos.x=0;
			world.update_world(world.world_pos.add(new vec3(1,0,0)));		}

		if (pos.y<0)
		{
			pos.y=world.height-1;
			world.update_world(world.world_pos.add(new vec3(0,-1,0)));
		}

		if (pos.y>=world.height)
		{
			pos.y=0;
			world.update_world(world.world_pos.add(new vec3(0,1,0)));
		}	
		
		if (world.get_cube(pos).pos.z>-1)
		{
			this.pos=pos;
			this.pos.z=world.get_cube(this.pos).pos.z+1;		            
			this.update_pos();
		}	
		else
		{
			world.update_world(oldworldpos);
		}
	};
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

function wilderness_world(w,h)
{
    this.width=w;
    this.height=h;
    this.objs=[];
    this.plants=[];
    this.world_pos=new vec3(0,0,0);
    this.rnd_gen=new rnd_gen();
	this.my_name="no name";
	
    for (var y=0; y<h; y++)
    {
        for (var x=0; x<w; x++)
        {
            this.objs.push(new cube(new vec3(0,0,0)));
        }
    }
    	
/*	public function NameCallback(name)
	{
		removeChild(MyTextEntry);
		WorldClient.Identify(name);
		MyName=name;
		WorldClient.GetPlants(cast(WorldPos.x,Int),cast(WorldPos.y,Int));
	}
*/	
	this.update_world = function(pos)
	{
		this.world_pos=pos;
		
		var circles = [];		
		this.plants = [];
		
		for (var x=-1; x<2; x++)
		{
			for (var y=-1; y<2; y++)
			{
				this.rnd_gen.seed((this.world_pos.x+x)+(this.world_pos.y+y)*139);
				
				for (var i=0; i<5; i++)
				{
				    this.rnd_gen.rnd_flt();
				    this.rnd_gen.rnd_flt();
				    this.rnd_gen.rnd_flt();
				    this.rnd_gen.rnd_flt();
					var pos = new vec3(this.rnd_gen.rnd_flt()*10+x*10,
                                       this.rnd_gen.rnd_flt()*10+y*10,
                                       0);
									  
						  
					circles.push(new circle(pos, this.rnd_gen.rnd_flt()*5));
				}
			}
		}
		
		
		for (i in this.objs)
		{
			var pos=new vec3(i%this.width,Math.floor(i/this.width),-1);
			this.rnd_gen.seed(this.world_pos.x+pos.x+this.world_pos.y+pos.y*139);
            this.rnd_gen.rnd_flt();
            this.rnd_gen.rnd_flt();
            this.rnd_gen.rnd_flt();
            this.rnd_gen.rnd_flt();
	
			var inside=false;
			for (c in circles)
			{
				if (circles[c].inside(pos)) pos.z=0;
			}
			this.objs[i].pos=pos;
			this.objs[i].update_pos(); 
			this.objs[i].update_tex(this.rnd_gen);
		}
		
		//WorldClient.GetPlants(cast(WorldPos.x,Int),cast(WorldPos.y,Int));
	};
		
	this.get_cube = function(pos)
	{
		return this.objs[pos.x+pos.y*this.width];
	};
		
	this.plant_tex = function(i)
	{
		var l = ["flowers.png","canopy.png","climber.png","lollypop.png"];
		return l[i];
	};
	
	/*public function OnServerPlantsCallback(ServerPlants:Array<ServerPlant>)
	{
		for (splant in ServerPlants)
		{
			var plant = new Entity(new Vec3(splant.x,splant.y,1),PlantTex(splant.type));
			addChild(plant);
			Plants.push(plant);
		}
    }
    */
	
	this.add_server_plant = function(pos)
	{
		// call by reference! :S
		var type = Math.floor(Math.random()*4);       
		this.plants.push(new plant(this.my_name,new vec3(pos.x,pos.y,1),this.plant_tex(type)));
		//WorldClient.AddPlant(cast(WorldPos.x,Int), cast(WorldPos.y,Int), 
		//				 new ServerPlant(MyName,cast(pos.x,Int),cast(pos.y,Int),type));
    }
	
	this.update = function(frame)
	{
		this.player.update(frame,this);
		for (var plant in this.plants)
		{
			this.plants[plant].update(frame,this);
		}
	};

    this.draw = function(ctx)
    {
		for (var obj in this.objs)
		{
            ctx.save();
			this.objs[obj].draw(ctx);
            ctx.restore();   
		}
        
		for (var plant in this.plants)
		{
            ctx.save();
			this.plants[plant].draw(ctx); 
            ctx.restore();   
		}        
        ctx.save();
        this.player.draw(ctx);
        ctx.restore();   
    };
	
	this.handle = function(e)
	{
		this.player.handle(e,this);
	};

    this.update_world(new vec3(0,0,0));	
    this.player = new player_entity(new vec3(5,5,1));

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

function wilderness()
{
	this.frame = 0;
	this.world = new wilderness_world(10,10);

	this.on_key_down = function(e)
	{
		this.world.handle(e);
	};
        
    this.update = function() 
	{
		this.world.update(this.frame);
		this.frame++;
        this.draw();    
	};
                       
    this.draw = function()
    {
        var ctx = document.getElementById('canvas').getContext('2d');  
        ctx.globalCompositeOperation = 'source-over';  
        ctx.clearRect(0,0,640,480); // clear canvas  
    
        ctx.fillStyle = 'rgba(0,0,0,0.4)';  
        ctx.strokeStyle = 'rgba(0,153,255,0.4)';  
        ctx.save(); 
	
        this.world.draw(ctx);

        ctx.restore();      
    };
}

var w = new wilderness();

function key_callback(e)
{
    w.on_key_down(e);
}

function callback()
{
    w.update();
}

function start()
{
    setInterval(callback,200);
    $(document).keydown(key_callback);
}
