module br.enemy;
private import str = std.string;
private import util.parts;
private import util.shape;
private import util.vector;
private import util.matrix;
private import util.log;
private import util.particle;
private import util.ring;
private import br.blast;
private import br.sound;
private import br.gamemanager;
private import std.math;
private import br.mainloop;
private import opengl;
private import SDL_mixer;

public class Enemy:Parts,Caller{
	private:
	double hp;
	double maxHp;
	bool vincible;
	bool border;
	bool inStage;
	double damage;
	static const int DIVISION = 8;
	static double[] si;
	static double[] co;
	public this(double hp,double R = -1,double G = -1 ,double B = -1 ,double alpha = -1){
		if(R < 0.0 || G < 0.0 || B < 0.0 || alpha < 0.0){
			if(hp < 0){
				this.R = 1.0; this.G = 1.0; this.B = 0.95; this.alpha = 1.0;
			}else{
				
				this.R=0.7; this.G=0.75; this.B=1.0; this.alpha=1.5;
			}
		}else{
			this.R = R;
			this.G = G;
			this.B = B;
			this.alpha = alpha;
		}
		if(hp < 0){
			this.hp = 100;
			vincible = false;
		}else{
			this.hp = hp;
			
			vincible = true;
		}
		
		maxHp = this.hp;
		border = true;
		inStage = false;
		damage = 0;
		enemyManager.add(this);
		collisionManager.add(this, collisionManager.kind.SHIP ,2);
		collisionManager.add(this, collisionManager.kind.SWORD ,2);
		drawing = POLYGON | WIRE;
		
		}
	public void  move(){
		super.move();
//		moveImpl();
		if(border &&(rpos.y+size < screen.GAME_DOWN || screen.GAME_UP < rpos.y-size ||
			screen.GAME_RIGHT  < rpos.x-size || rpos.x+size < screen.GAME_LEFT 
			)){
			if(inStage || 300 < cnt )vanish();
			
		}else inStage = true;
		
		if(screen.GAME_NEAR < rpos.z - size || rpos.z + size < screen.GAME_FAR){
			vanish();
		}
		if((1e-6) < damage){
			
			double radZ ,radX;
			radZ = rand.nextFloat(PI * 2.0);
			radX = rand.nextFloat(PI);
			vibrate(radZ ,radX ,damage);
			
			damage -= 0.1;
		}else damage = 0.0;
	}
	public void disableBorder(){
		border = false;
	}
	public void addChild(inout Parts child,char[] name, double dist = 0.1, int childKind = NORMAL, Matrix link = null ,Matrix pose = null){
		super.addChild(child ,name ,dist ,childKind ,link ,pose);
		enemyManager.add(child);
//		if(vincible)super.setColor(R ,G ,B ,alpha);
	}
	public void setColor(double R ,double G ,double B ,double alpha){
		if(vincible)super.setColor(R ,G ,B ,alpha);
	}
	public void setTarget(){
		setColor(1.0,0.7,0.8,1.5);
		
		/*
		foreach(Parts child;cast(Parts[])childHash.values){
			child.setColor(R ,G ,B ,alpha);
		}
		*/
	}
	public void draw(){
		super.draw();
		if(si.length == 0){
			si.length = DIVISION;
			for(int i=0;i<DIVISION;i++){
				si[i] = sin(PI *2.0 * cast(double)i / DIVISION);
			}
		}
		if(co.length == 0){
			co.length = DIVISION;
			for(int i=0;i<DIVISION;i++){
				co[i] = cos(PI *2.0 * cast(double)i / DIVISION);
			}
		}
		if(vincible){
			//double R,G,B,alpha;
			//R=1.0; G=0.85;B=0.9;alpha=1.0;
			double ihp =ceil(hp);
			double radius;
			double rsize;
			double dist = size * 1.8;
			double R ,G ,B;
			double alpha = this.alpha * 0.7;
			R = fmin(1.0 ,(this.R + 0.05) * (this.R + 0.05));
			G = fmin(1.0 ,(this.G + 0.05) * (this.G + 0.05));
			B = fmin(1.0 ,(this.B + 0.05) * (this.B + 0.05));
			for(double i=0;i<hp;i+= 1.0){
				glPushMatrix();
				double rad = (-cast(double)(cnt%150)/150.0 + cast(double)i/ihp) * PI * 2.0;
				if(i < floor(hp))rsize = 15.0;
				else rsize = fmax(5.0 ,(hp - i) * 15.0);
				//rsize = 10.0;
				if(cnt % 30 < 15)radius = rsize *(1.0 - cast(double)(cnt % 15) /15.0 * 0.2);
				else radius = rsize * (1.0 - cast(double)((cnt - 15) % 15) /15.0 * 0.2);
				radius *= 0.7;
				//radius = 15.0;
				glTranslatef(cos(rad) * dist, sin(rad) * dist ,0.0);
				for(int j=0;j<DIVISION-1;j++){
					
					glBegin(GL_POLYGON);
					glColor3f(R * alpha * 0.3,G * alpha * 0.3 ,B * alpha * 0.3);
	//				glColor4f(R,G,B,0.0);
					glVertex3f(radius*co[j],radius*si[j] ,0.0);
					glVertex3f(radius*co[j+1],radius*si[j+1] ,0.0);
					glColor3f(R * alpha,G * alpha ,B * alpha);
	//				glColor4f(R,G,B,alpha);
					glVertex3f(0.0,0.0 ,0.0);
					
					glEnd();
				}
				glBegin(GL_POLYGON);
				glColor3f(R * alpha * 0.3,G * alpha * 0.3 ,B * alpha * 0.3);
	//			glColor4f(R,G,B,0);
				glVertex3f(radius*co[0],radius*si[0] ,0.0);
				glVertex3f(radius*co[DIVISION-1],radius*si[DIVISION-1] ,0.0);
				glColor3f(R * alpha,G * alpha ,B * alpha);
	//			glColor4f(R,G,B,alpha);
				glVertex3f(0.0,0.0 ,0.0);
				glEnd();
				glPopMatrix();
			}
		}
		
	}
	public void reportRing(Ring ring){
	}
	public void destroy(){
		super.destroy();
		if(maxHp < 2.0)makeSimpleParticle(4 ,size ,WIRE ,rpos ,R ,G ,B ,alpha * 0.5);
		else makeParticle(shape, size ,WIRE ,rpos ,new Vector3() ,rpose ,R ,G ,B ,alpha);
		new SmallBlast(rpos.x ,rpos.y ,20 ,20 ,10.0 ,90 ,R ,G ,B ,0.1);
	}
	public void vanish(){
		super.vanish();
	}
	public override void reportCollision(int kind){
		switch(kind){
			case collisionManager.kind.SWORD:
			
			double d;
			d = 1.0;//0.5 + 0.6 * fmin(1.0 ,fmax(0.0 ,(ship.laserSpeed - ship.laserMinSpeed) / (ship.laserMaxSpeed - ship.laserMinSpeed)));
			if(vincible){
				hp = hp - d;//fmax(ceil(hp-1.0) ,hp - d);
				if(hp <= 0)destroy();
				Sound_PlaySe(se_kind.SLASH);
//				Mix_PlayChannel(-1, chunk_slash, 0);
				
			}else{
				Sound_PlaySe(se_kind.DEFEND);
//				Mix_PlayChannel(-1, chunk_defend, 0);
				d *= 0.3;
			}
			
			damage = fmin(3.0 ,damage+d);
			
			break;
			default:break;
		}
	}
	public bool exists(){
		return super.exists;
	}
}
public class Boss:Enemy{
	public:
	char[] state;
	int nowStateCnt;
	public this(double hp,double R = -1.0,double G = -1.0 ,double B = -1.0 ,double alpha = -1.0){
		
		if(R < 0.0 || G < 0.0 || B < 0.0 || alpha < 0.0){
			R=0.9; G=0.45; B=1.0; alpha=1.5;
		}
		super(hp ,R ,G ,B ,alpha);
		nowStateCnt = 0;
		disableBorder();
		state = "start";
	}
	public void changeState(char[] state){
		this.state = state.dup;
		nowStateCnt = -1;
	}
	public void destroy(){
		super.destroy();
//		makeParticle(shape, size ,WIRE ,rpos ,new Vector3() ,rpose ,R ,G ,B ,alpha * 2.0);
		new Blast(rpos.x ,rpos.y ,20.0 ,15.0 ,90 ,R ,G ,B ,0.2);
		Sound_PlaySe(se_kind.BOMB);
//		Mix_PlayChannel(-1, chunk_bomb, 0);
	}
	public void move(){
		super.move();
		nowStateCnt ++;
	}
	
}

public class AttackRing:Ring{
	public this(Enemy caller ,char[] name ,int span ,double R=1.0 ,double G=0.4,double B=1.0,double alpha =1.0){
		super(caller ,caller.rpos ,name ,span ,R ,G ,B ,alpha);
		
	}
	
}