package dangerzone.entities;



import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

import org.newdawn.slick.opengl.Texture;


import dangerzone.DamageTypes;
import dangerzone.DangerZone;
import dangerzone.InventoryContainer;
import dangerzone.TextureMapper;
import dangerzone.Utils;
import dangerzone.World;
import dangerzone.entities.Entity;

import dangerzone.entities.ThrownBlockItem;
import dangerzone.items.Items;

public class EntityMagic extends ThrownBlockItem {
	
	public float spin = 0;
	double oposx, oposy, oposz;
	
	public Texture texture_black;
	public Texture texture_white;
	public Texture texture_orange;
	public Texture texture_yellow;
	public Texture texture_blue;
	public Texture texture_purple;
	public Texture texture_green;
	public Texture texture_red;

	
	int mycolor = 0;
	float omx, omy, omz = 0; //remember our direction!
	List<Entity> enchanted_list = null;
	
	public EntityMagic(World w) {
		super(w);
		setAttackDamage(100.0f);
		uniquename = "DangerZone:EntityMagic";
		maxrenderdist = 200; //in blocks
		oposx = 0;
		oposy = 0;
		oposz = 0;
		deathtimer = 15; // 1.5 seconds
		if(w != null)mycolor = w.rand.nextInt(8);
		enchanted_list = new ArrayList<Entity>();
	}
	
	public float getWidth(){
		return getScale();
	}
	
	public float getHeight(){
		return getScale();
	}
	
	public void doEntityAction( float deltaT){

		if(getBID() != 0){ //master
			if(omx == 0 && omy == 0 && omz == 0){
				omx = motionx;
				omy = motiony;
				omz = motionz;
				motionx = motiony = motionz = 0;
				deathtimer = 30;
				oposx = posx;
				oposy = posy;
				oposz = posz;
				
					world.playSound("DangerZone:magic1", dimension, posx, posy, posz, 1, 1);
				
			}
			deathtimer--;
			if(deathtimer <= 0){
				this.deadflag = true;
				return;
			}

			if(deathtimer < 16){
				motionx = omx;
				motiony = omy;
				motionz = omz;

				doFindThings(deltaT, true);

			}else{
				EntityMagic e = (EntityMagic)this.world.createEntityByName("DangerZone:EntityMagic", dimension, oposx, oposy, oposz);
				if(e != null){
					e.init();
					e.setIID(getIID());				//so it can know if it is normal scroll or not...
					e.setVarInt(3, getVarInt(3));	//harm or heal for now...
					e.thrower = this;					
					e.motionx = omx + (world.rand.nextFloat()-world.rand.nextFloat())*0.15f;
					e.motiony = omy + (world.rand.nextFloat()-world.rand.nextFloat())*0.15f;
					e.motionz = omz + (world.rand.nextFloat()-world.rand.nextFloat())*0.15f;				
					this.world.spawnEntityInWorld(e);
				}
			}

		}else{

			//motiony -= 0.16f * deltaT; //gravity-ish

			doFindThings(deltaT, false);


			deathtimer--;
			if(deathtimer <= 0){
				this.deadflag = true;
				//System.out.printf("max size = %f\n",  getWidth());
			}
		}

	}
	
	public void doFindThings(float deltaT, boolean enchant){
		//Check for hitting a block...
		float dist = (float)Math.sqrt(motionx*deltaT*motionx*deltaT + motiony*deltaT*motiony*deltaT + motionz*deltaT*motionz*deltaT);
		float blockdist = 0;
		float edist = 0;
		List<Entity> hit_list = null;
		List<Entity> nearby_list = null;
		ListIterator<Entity> li;
		ListIterator<Entity> hli;
		Entity enthit = null;
		Entity henthit = null;
		double fx, fy, fz;
		boolean doit = true;

		//Get a list of entities within reach of largest mob expected because we may hit their hitbox!
		nearby_list = DangerZone.server.entityManager.findALLEntitiesInRange(16.0f+dist, dimension, posx, posy, posz);
		hit_list = new ArrayList<Entity>();

		fx = posx;
		fy = posy;
		fz = posz;


		/*
		 * increment along in the direction we are heading to see if we hit something.
		 * We do this, because we can move more (a lot!) than one block distance in a clock tick!
		 */
		while(dist > 0 && blockdist < dist){
			fx = posx + motionx*deltaT*blockdist/dist;
			fy = posy + motiony*deltaT*blockdist/dist;
			fz = posz + motionz*deltaT*blockdist/dist;

			li = nearby_list.listIterator();
			while(li.hasNext()){
				enthit = (Entity)li.next();
				if(enthit instanceof EntityBlockItem || (getIID() < 0 && enthit instanceof EntityLiving && enthit != thrower)){
					if(fy > enthit.posy-(getWidth()/2)  && fy < enthit.posy+enthit.getHeight()+(getWidth()/2) ){
						edist = (float) enthit.getHorizontalDistanceFromEntity(fx, fz); //Center of tip to center of entity
						edist -= getWidth()/2; //width of me
						edist -= (enthit.getWidth()/2); //general hitbox of entity
						if(edist < 0){
							//Hit something!
							doit = true;
							hli = hit_list.listIterator();
							while(hli.hasNext()){
								henthit = (Entity)hli.next();
								if(henthit == enthit){
									doit = false;
									break;
								}
							}

							if(doit){
								if(enchant){
									doEnchantSomething(false , fx, fy, fz, true, enthit);
								}else{
									doHitSomething(false , fx, fy, fz, true, enthit);
								}
								hit_list.add(enthit);
							}
						}
					}
				}

			}

			doSpecialEffects(fx, fy, fz);

			blockdist += 0.25f;
		}
	}
	
	//override for when we hit something
	public void doHitSomething(boolean hb, double x, double y, double z, boolean he, Entity ent){
		Utils.spawnParticlesFromServer(world, "DangerZone:ParticleSparkle", 10, ent.dimension, ent.posx, ent.posy, ent.posz);		
	}
	
	public void doEnchantSomething(boolean hb, double x, double y, double z, boolean he, Entity ent){
		
		if(getIID() < 0){ //effect on entity!			
			if(getVarInt(3)!=0){
				Utils.spawnParticlesFromServer(world, "DangerZone:ParticleHappy", 50, ent.dimension, ent.posx, ent.posy, ent.posz);	
				ent.heal(ent.getMaxHealth()/3); //very powerful healing spell!
			}else{
				Utils.spawnParticlesFromServer(world, "DangerZone:ParticleDeath", 50, ent.dimension, ent.posx, ent.posy, ent.posz);	
				float eh = ent.getHealth()/8;
				if(eh < 20)eh = 20;
				ent.doAttackFromCustom(thrower, DamageTypes.MAGIC, eh, false);
			}
		}else{
			Utils.spawnParticlesFromServer(world, "DangerZone:ParticleSparkle", 50, ent.dimension, ent.posx, ent.posy, ent.posz);	
			InventoryContainer ic = ent.getInventory(0); //fetch what it is carrying
			if(ic.bid == 0 && ic.iid != 0){
				if(Items.getMaxStack(ic.iid) == 1){
					//only once!
					ListIterator<Entity> hli;
					Entity henthit = null;
					hli = enchanted_list.listIterator();
					while(hli.hasNext()){
						henthit = (Entity)hli.next();
						if(henthit == ent){
							return;
						}
					}
					ic.addAttribute(getIID(), getVarInt(2)); //increment attribute!				
					world.playSound("DangerZone:magic2", dimension, posx, posy, posz, 1, 1);				
				}
			}
		}
	}
	
	public float getDensity(){
		float d = 1.5f/getScale();
		if(d > 1)d = 1;
		return d;
	}
	
	public float getSpinz(){
		spin += 5;
		return spin;
	}
	
	public float getScale(){
		if(oposx == 0){
			oposx = posx;
			oposy = posy;
			oposz = posz;
		}
		double d1, d2, d3;
		d1 = oposx - this.posx;
		d2 = oposy - this.posy;
		d3 = oposz - this.posz;
		float scale = (float) Math.sqrt((d1*d1)+(d2*d2)+(d3*d3));
		if(scale < 2)scale = 2;
		if(getIID() < 0)return scale/10;
		return scale/20;
	}
	
	//Model calls back out to see what texture to use.
	public Texture getTexture(){
		if(getBID() != 0)return null; //invisible master
		if(getIID() < 0){ //special 
			if(getVarInt(3) == 0){
				mycolor = 7;
			}else{
				mycolor = 6;
			}
		}
		
		if(mycolor == 0){
			if(texture_black == null){
				texture_black = TextureMapper.getTexture("res/skins/magic_black.png");
			}
			return texture_black;
		}
		if(mycolor == 1){
			if(texture_white == null){
				texture_white = TextureMapper.getTexture("res/skins/magic_white.png");
			}
			return texture_white;
		}
		if(mycolor == 2){
			if(texture_orange == null){
				texture_orange = TextureMapper.getTexture("res/skins/magic_orange.png");
			}
			return texture_orange;
		}
		if(mycolor == 3){
			if(texture_yellow == null){
				texture_yellow = TextureMapper.getTexture("res/skins/magic_yellow.png");
			}
			return texture_yellow;
		}
		if(mycolor == 4){
			if(texture_blue == null){
				texture_blue = TextureMapper.getTexture("res/skins/magic_blue.png");
			}
			return texture_blue;
		}
		if(mycolor == 5){
			if(texture_purple == null){
				texture_purple = TextureMapper.getTexture("res/skins/magic_purple.png");
			}
			return texture_purple;
		}
		if(mycolor == 6){
			if(texture_green == null){
				texture_green = TextureMapper.getTexture("res/skins/magic_green.png");
			}
			return texture_green;
		}
		if(mycolor == 7){
			if(texture_red == null){
				texture_red = TextureMapper.getTexture("res/skins/magic_red.png");
			}
			return texture_red;
		}
		return null;
	}

}
