module br.stage;

private import util.vector;
private import std.math;

private import br.gamemanager;

private import br.screen;
private import br.ship;
private import br.mainloop;
private import br.screen;
private import br.sound;
private import br.frame;
private import br.enemy;
private import br.star;
private import br.bullet;
private import br.wall;
private import br.pattern;
private import br.background;


public class Stage{
	private int music;
	private long cnt;
	private long cnt1;
	private ObjectData[] enemyData;
	private ObjectData[] wallData;
	private StarData[] starData;
	private int enemyNum;
	private int wallNum;
	private int starNum;
	private int enemyPointer;
	private int wallPointer;
	private int starPointer;
	private int enemyCnt;
	private int wallCnt;
	private int starCnt;
	private bool _complete;
	public BackGround bg;
	
	private Enemy target;
	public this(){
		cnt = 0;
		cnt1 = 0;
		enemyData.length = 16;
		enemyNum = 0;
		starData.length = 16;
		starNum = 0;
		wallData.length = 16;
		wallNum = 0;
		target= null;
		
		set();
		enemyPointer = 0;
		wallPointer = 0;
		starPointer = 0;
		enemyCnt = 0;
		wallCnt = 0;
		starCnt = 0;
//		bg = new Back1();
		_complete = false;
	}
	public void start(){
		if(Sound_PlayingMusic != music && Sound_PlayingMusic >= 0){
			Sound_FadeOutMusic(1000);
		}else Sound_FadeInMusic(music, 2000);
	}
	public void addEnemyData(int time ,char[] type ,float posx ,float posy ,float v ,double angle ,Object par = null ,bool target=false){
		ObjectData e = new ObjectData(time ,type.dup ,new Vector3(posx ,posy ,-800)
		 ,new Vector3(v*cos(angle*PI/180.0) ,v*sin(angle*PI/180.0) ,0.0f) ,par ,target);
		if(enemyNum < enemyData.length)enemyData[enemyNum] = e;
		else{
			enemyData.length = enemyData.length * 2;
			enemyData[enemyNum] = e;
		}
		enemyNum ++;
	}
	public void addWallData(int time ,char[] type ,float posx ,float posy ,float v ,double angle = -90.0 ,Object par = null){
		ObjectData w = new ObjectData(time ,type.dup ,new Vector3(posx ,posy ,-800)
		 ,new Vector3(v*cos(angle*PI/180.0) ,v*sin(angle*PI/180.0) ,0.0f) ,par);
		if(wallNum < wallData.length)wallData[wallNum] = w;
		else{
			wallData.length = wallData.length * 2;
			wallData[wallNum] = w;
		}
		wallNum ++;
	}
	
	public void addStarData(int time ,int right){
		StarData s = new StarData(time ,right);
		
		if(starNum < starData.length)starData[starNum] = s;
		else{
			starData.length = starData.length * 2;
			starData[starNum] = s;
		}
		starNum ++;
	}
	
	public void run(){
		if(cnt == 90)Sound_FadeInMusic(music, 2000);
		if(target is null){
			ObjectData e;
//			for(int i=0;i<enemyNum;i++){
			bool m;//=false;
			do{
				m = false;
				if(enemyNum <= enemyPointer){
					_complete = true;
					break;
				}
				
				e = enemyData[enemyPointer];
				if(!e.made){
					if(enemyCnt >= divsp(e.time)){
						Enemy ene=makeEnemy(e.type ,e.pos ,e.vel ,e.par);
						if(ene !is null){
							if(e.target)target = ene;
						}
						e.made = true;
						enemyPointer ++;
						enemyCnt = 0;
						m = true;
					}
				}
				if(target !is null)break;
			}while(m);
			enemyCnt ++;
		}
		if(target is null){
			ObjectData w;
//			for(int i=0;i<wallNum;i++){
			bool m;//=false;
			do{
				m = false;
				if(wallNum <= wallPointer)break;
				
				w = wallData[wallPointer];
				if(!w.made){
					if(wallCnt >= divsp(w.time)){
						makeWall(w.type ,w.pos ,w.vel ,w.par);
						w.made = true;
						wallPointer ++;
						wallCnt = 0;
						m = true;
					}
				}
			}while(m);
			wallCnt ++;
			
//			m = false;
			StarData s;
			do{
//			for(int i=0;i<starNum;i++){
				m = false;
				if(starNum <= starPointer)break;
				s = starData[starPointer];
				if(!s.made){
					if(starCnt >= divsp(s.time)){
						new Star1(new Vector3(s.right*(Ship.RIGHTX-Ship.LEFTX) +Ship.LEFTX ,Screen.GAME_UP ,-800) ,new Vector3(0.0f ,-3.0f ,0));
						s.made = true;
						starPointer ++;
						starCnt = 0;
						m = true;
					}
					
				}
			}while(m);
			starCnt ++;
			cnt ++;
		}else {
			if(!target.exists)target = null;
		}
		
		/*
		if(cnt1 % cast(int)(divsp(100)) == 0){
//			float z = -1200.0f;
			for(float z = -400;-1200<z;z-=200.0f){
				for(float x = -200;x<=200;x += 100){//114){
					Vector3 pos = new Vector3(x ,Screen.GAME_UP+60 ,z);
					Vector3 vel = new Vector3(0.0f ,-1.0f ,0);
					new Pattern2(pos ,vel);
				}
			}
		}
		*/
		
		
		
		cnt1 ++;
	}
	
	public void set(){
		/*
		for(float z = -400;-1200<z;z-=200.0f){
			for(float y=-200;y<240;y+=100){
				for(float x = -200;x<=200;x += 100){//114){
					Vector3 pos = new Vector3(x ,y ,z);
					Vector3 vel = new Vector3(0.0f ,-1.0f ,0);
					new Pattern2(pos ,vel);
				}
			}
		}
		*/	
		setSound();
		setEnemies();
		setWalls();
		setStars();
		
	}
	void setSound(){
		
	}
	void setEnemies(){
		
	}
	
	void setWalls(){
		
	}
	
	void setStars(){
		
	}
	
	public bool complete(){
		return _complete;
	}
}
public class ObjectData{
	public int time;
	public char[] type;
	public Vector3 pos;
	public Vector3 vel;
	public Object par;
	public bool target;
	public bool made;
	public this(int time ,char[] type ,Vector3 pos ,Vector3 vel ,Object par = null ,bool target = false){
		this.time = time;
		this.type = type.dup;
		this.pos = cast(Vector3)pos.clone();
		this.vel = cast(Vector3)vel.clone();
		this.par =par;
		this.target = target;
		this.made = false;
	}
}

public class StarData{
	public int time;
	public int right;
	public bool made;
	public this(int time ,int right){
		this.time = time;
		this.right =right;
		this.made = false;
	}
}
public class Stage1:Stage{
	public this(){
		super();
		bg = new Back1();
		
	}
	void setSound(){
		music = music_kind.MUSIC1;
	}
	void setEnemies(){
	
	
//		addEnemyData(30 ,"laser" ,0 ,240 ,1.0 ,-90);
		
		
//		addEnemyData(60 ,"boss1" ,0 ,300 ,0 ,0 ,null ,true);
		for(int i=0;i<300;i+=15){
			addEnemyData(15 ,"c" ,rand.nextFloat(360)-180.0f ,240 ,3.0f ,-90 + rand.nextFloat(60) - 30,null);
		}
		
		
		
		addEnemyData(30 ,"d" ,-180 ,240 ,5.0f ,-80,null);
		addEnemyData(40 ,"d" ,180 ,240 ,5.0f ,-100,null);
		addEnemyData(40 ,"d" ,-180 ,240 ,5.0f ,-80,null);
		addEnemyData(40 ,"d" ,180 ,240 ,5.0f ,-100,null);
		addEnemyData(40 ,"d" ,-180 ,240 ,5.0f ,-80,null);
		/*
		for(int i=0;i<150;i+=80){
			addEnemyData(40 ,"d" ,180 ,240 ,5.0f ,-100,null);
			addEnemyData(40 ,"d" ,-180 ,240 ,5.0f ,-80,null);
		}
		*/
		
//		addEnemyData(40 ,"d" ,-180 ,240 ,5.0f ,-80,null);
		for(int i=0;i<300;i+=70){
			addEnemyData(15 ,"d" ,-180+rand.nextFloat(20)-10 ,240 ,5.0f ,-80,null);
			for(int j=0;j<1;j++){
				addEnemyData(20 ,"c" ,rand.nextFloat(120)+40.0f ,240 ,3.0f ,-90 + rand.nextFloat(60) - 30,null);
			}
			addEnemyData(15 ,"d" ,-20+rand.nextFloat(20)-10 ,240 ,5.0f ,-100,null);
			for(int j=0;j<1;j++){
				addEnemyData(20 ,"c" ,rand.nextFloat(120)+40.0f ,240 ,3.0f ,-90 + rand.nextFloat(60) - 30,null);
			}
		}
		
		for(int i=0;i<=350;i+=70){
			addEnemyData(15 ,"d" ,20+rand.nextFloat(20)-10 ,240 ,5.0f ,-80,null);
			for(int j=0;j<1;j++){
				addEnemyData(20 ,"c" ,-rand.nextFloat(120)-40.0f ,240 ,3.0f ,-90 + rand.nextFloat(60) - 30,null);
			}
			addEnemyData(15 ,"d" ,180+rand.nextFloat(20)-10 ,240 ,5.0f ,-100,null);
			for(int j=0;j<1;j++){
				addEnemyData(20 ,"c" ,-rand.nextFloat(120)-40.0f ,240 ,3.0f ,-90 + rand.nextFloat(60) - 30,null);
			}
		}
		addEnemyData(60 ,"boss1" ,0 ,300 ,0 ,0 ,null ,true);

	}
	
	void setWalls(){
		/*
		for(int i=0;i<1200;i+=240){
			addWallData(i ,"1" ,rand.nextFloat(Screen.GAME_RIGHT - Screen.GAME_LEFT) + Screen.GAME_LEFT ,240 ,3 );
		}
		*/
	}
	
	void setStars(){
		for(int i=0;i<300;i+=60){
			addStarData(60 ,(i/60)%2);
		}
		for(int i=0;i<190;i+=60){
			addStarData(60 ,(i/60+1)%2);
		}
		//4
		for(int i=0;i<300;i+=60){
			int c = (i/60)%3;
			if(c==0)addStarData(60 ,1);
			else addStarData(60 ,0);
		}
		//9
		for(int i=0;i<=320;i+=60){
			int c = (i/60+1)%3;
			if(c==0)addStarData(60 ,0);
			else addStarData(60 ,1);
		}
		//14
	}
	
}
public class Stage2:Stage{
	public this(){
		super();
		bg = new Back2();
		
	}
	void setSound(){
		music = music_kind.MUSIC1;
	}
	void setEnemies(){
		
		
		
		addEnemyData(60 ,null ,0 ,0 ,0.0f ,0);
		for(int i=0;i<=160;i+=40){
			addEnemyData(20 ,"d" ,rand.nextFloat(300)-180 ,240 ,rand.nextFloat(3.0f)+4.0f ,-80,null);
			addEnemyData(20 ,"d" ,-rand.nextFloat(300)+180 ,240 ,rand.nextFloat(3.0f)+4.0f ,-100,null);
		}
		//220
		addEnemyData(60 ,null ,0 ,0 ,0.0f ,0);
		addEnemyData(30 ,"e" ,-180 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"capsule" ,-20 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"e" ,-180 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"capsule" ,-20 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"e" ,-180 ,240 ,3.0f ,-90,null);
		//370

		addEnemyData(30 ,"1" ,-80 ,240 ,3.0f ,-90,null);
		addEnemyData(30 ,"1" ,0 ,240 ,3.0f ,-90,null);
		addEnemyData(30 ,"1" ,80 ,240 ,3.0f ,-90,null);
		addEnemyData(60 ,null ,0 ,0 ,0.0f ,0);
		//510
		
		addEnemyData(0 ,"e" ,180 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"capsule" ,20 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"e" ,180 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"capsule" ,20 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"e" ,180 ,240 ,3.0f ,-90,null);
		addEnemyData(30 ,"1" ,80 ,240 ,3.0f ,-90,null);
		addEnemyData(30 ,"1" ,0 ,240 ,3.0f ,-90,null);
		addEnemyData(30 ,"1" ,-80 ,240 ,3.0f ,-90,null);
		//660
		
		addEnemyData(60 ,null ,0 ,0 ,0.0f ,0);
		addEnemyData(0 ,"e" ,-180 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"capsule" ,-20 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"e" ,-180 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"capsule" ,-20 ,240 ,3.0f ,-90,null);
		addEnemyData(15 ,"e" ,-180 ,240 ,3.0f ,-90,null);
		//780
		
		addEnemyData(120 ,null ,0 ,0 ,0.0f ,0);
		for(int i=0;i<=160;i+=40){
			addEnemyData(20 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
			addEnemyData(20 ,"f" ,-rand.nextFloat(300)+180 ,240 ,3.0f ,-100,null);
		}
		/*
		for(int i=0;i<=120;i+=80){
			addEnemyData(40 ,"f" ,rand.nextFloat(300)-180 ,240 ,4.0f ,-80,null);
			addEnemyData(40 ,"f" ,-rand.nextFloat(300)+180 ,240 ,4.0f ,-100,null);
		}
		*/
		addEnemyData(90 ,"capsule" ,-160 ,240 ,2.0f ,-90 ,null );
		addEnemyData(0 ,"capsule" ,-120 ,240 ,2.0f ,-90 ,null);
		addEnemyData(0 ,"capsule" ,-80 ,240 ,2.0f ,-90 ,null);
//		addEnemyData(40 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
		addEnemyData(30 ,"mine" ,-160 ,240 ,2.0f ,-90 ,null );
		addEnemyData(0 ,"mine" ,-120 ,240 ,2.0f ,-90 ,null);
		addEnemyData(0 ,"mine" ,-80 ,240 ,2.0f ,-90 ,null);
		/*
		for(int i=0;i<=160;i+=80){
			addEnemyData(40 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
			addEnemyData(40 ,"f" ,-rand.nextFloat(300)+180 ,240 ,3.0f ,-100,null);
		}
		*/
		addEnemyData(90 ,"capsule" ,160 ,240 ,2.0f ,-90 ,null );
		addEnemyData(0 ,"capsule" ,120 ,240 ,2.0f ,-90 ,null);
		addEnemyData(0 ,"capsule" ,80 ,240 ,2.0f ,-90 ,null);
//		addEnemyData(40 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
		addEnemyData(30 ,"mine" ,160 ,240 ,2.0f ,-90 ,null );
		addEnemyData(0 ,"mine" ,120 ,240 ,2.0f ,-90 ,null);
		addEnemyData(0 ,"mine" ,80 ,240 ,2.0f ,-90 ,null);
		/*
		for(int i=0;i<=160;i+=80){
			addEnemyData(40 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
			addEnemyData(40 ,"f" ,-rand.nextFloat(300)+180 ,240 ,3.0f ,-100,null);
		}
		*/
		addEnemyData(90 ,"capsule" ,-160 ,240 ,2.0f ,-90 ,null );
		addEnemyData(0 ,"capsule" ,-120 ,240 ,2.0f ,-90 ,null);
		addEnemyData(0 ,"capsule" ,-80 ,240 ,2.0f ,-90 ,null);
//		addEnemyData(40 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
		addEnemyData(30 ,"mine" ,-160 ,240 ,2.0f ,-90 ,null );
		addEnemyData(0 ,"mine" ,-120 ,240 ,2.0f ,-90 ,null);
		addEnemyData(0 ,"mine" ,-80 ,240 ,2.0f ,-90 ,null);
		/*
		for(int i=0;i<=160;i+=80){
			addEnemyData(40 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
			addEnemyData(40 ,"f" ,-rand.nextFloat(300)+180 ,240 ,3.0f ,-100,null);
		}
		*/
		addEnemyData(90 ,"capsule" ,160 ,240 ,2.0f ,-90 ,null );
		addEnemyData(0 ,"capsule" ,120 ,240 ,2.0f ,-90 ,null);
		addEnemyData(0 ,"capsule" ,80 ,240 ,2.0f ,-90 ,null);
//		addEnemyData(40 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
		addEnemyData(30 ,"mine" ,160 ,240 ,2.0f ,-90 ,null );
		addEnemyData(0 ,"mine" ,120 ,240 ,2.0f ,-90 ,null);
		addEnemyData(0 ,"mine" ,80 ,240 ,2.0f ,-90 ,null);
		
		
		
		addEnemyData(150 ,"wall" ,rand.nextFloat(240.0f)-120.0f ,240 ,3.0f ,-90 ,null );
		for(int i=0;i<6;i++){
			
			addEnemyData(30 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
			addEnemyData(30 ,"f" ,-rand.nextFloat(300)+180 ,240 ,3.0f ,-100,null);
			addEnemyData(30 ,"f" ,rand.nextFloat(300)-180 ,240 ,3.0f ,-80,null);
			addEnemyData(20 ,"wall" ,rand.nextFloat(240.0f)-120.0f ,240 ,3.0f ,-90 ,null );
		}
		addEnemyData(60 ,"wall" ,rand.nextFloat(240.0f)-120.0f ,240 ,3.0f ,-90 ,null );
		for(int i=0;i<1;i++){
		
			addEnemyData(50 ,"wall" ,rand.nextFloat(240.0f)-120.0f ,240 ,3.0f ,-90 ,null );
		}
		addEnemyData(50 ,"wall" ,rand.nextFloat(240.0f)-120.0f ,240 ,3.0f ,-90 ,null ,true);
		addEnemyData(10 ,"boss2" ,0 ,300 ,0 ,0 ,null ,true);

	}
	
	void setWalls(){
		addWallData(260,null,0,0,0);
		makeCource(true ,100 ,160 ,3.0f ,1 ,2);
		addWallData(30,null,0,0,0);
		makeCource(false ,100 ,130 ,3.0f ,2 ,2);
		addWallData(30,null,0,0,0);
		makeCource(true ,100 ,130 ,3.0f ,2 );
		/*
		addWallData(280 ,"1" ,180 ,240 ,3 );
		
		for(int i=0;i<300;i+=7){
			addWallData(20 ,"1" ,180 ,240 ,3 );
			int w = cast(int)fmin(i*6 ,100); 
			for(int j=140;j>=140-w;j-=40){
				addWallData(0 ,"1" ,j ,240 ,3 );
			}
		}
		*/
		/*
		for(int i=0;i<1200;i+=7){
			addWallData(20 ,"1" ,20 ,240 ,3 );
			for(int j=60;j<200;j+=40){
				addWallData(0 ,"1" ,j ,240 ,3 );
			}
		}
		*/
	}
	
	void setStars(){
		for(int i=0;i<160;i+=60){
			addStarData(60 ,(i/60)%2);
		}
		addStarData(760 ,1);
		addStarData(60 ,0);
		addStarData(60 ,1);
		addStarData(790 ,1);
		for(int i=0;i<5;i++){
			addStarData(110 ,i%2);
		}
		/*
		for(int i=0;i<300;i+=60){
			int c = (i/60)%3;
			if(c==0)addStarData(60 ,1);
			else addStarData(60 ,0);
		}
		*/
	}
	private void makeCource(bool right ,int width ,int length ,float speed ,float sgra = -1,float egra = -1){
	int slen ,elen;
	if(sgra < 0)slen = 0;
	else slen = cast(int)(width / sgra);
	if(egra < 0)elen = 0;
	else elen = cast(int)(width / egra);
	
	int w;
	if(right){
		for(int i=0;i<slen;i+=40){//cast(int)(60/speed)){
			w = cast(int)fmin(i*sgra ,width); 
			addWallData(cast(int)(60/speed) ,"1" ,180 ,240 ,speed );
			for(int j=140;j>140-w;j-=40){
				addWallData(0 ,"1" ,j ,240 ,speed );
			}
		}
		for(int i=0;i<length -cast(int)((slen+elen)*60.0/(40.0*speed));i+=cast(int)(60/speed)){
			w = width; 
			addWallData(cast(int)(60/speed) ,"1" ,180 ,240 ,speed );
			for(int j=140;j>140-w;j-=40){
				addWallData(0 ,"1" ,j ,240 ,speed );
			}
		}
		for(int i=0;i<elen;i+=40){//cast(int)(60/speed)){
			w = cast(int)fmax(width-i*egra ,0); 
			addWallData(cast(int)(60/speed) ,"1" ,180 ,240 ,speed );
			for(int j=140;j>140-w;j-=40){
				addWallData(0 ,"1" ,j ,240 ,speed );
			}
		}
	}else{
		for(int i=0;i<slen;i+=40){
			w = cast(int)fmin(i*sgra ,width); 
			addWallData(cast(int)(60/speed) ,"1" ,-180 ,240 ,speed );
			for(int j=-140;j<-140+w;j+=40){
				addWallData(0 ,"1" ,j ,240 ,speed );
			}
		}
		for(int i=0;i<length -cast(int)((slen+elen)*60.0/(40.0*speed));i+=cast(int)(60/speed)){
			w = width; 
			addWallData(cast(int)(60/speed) ,"1" ,-180 ,240 ,speed );
			for(int j=-140;j<-140+w;j+=40){
				addWallData(0 ,"1" ,j ,240 ,speed );
			}
		}
		for(int i=0;i<elen;i+=40){
			w = cast(int)fmax(width-i*egra ,0); 
			addWallData(cast(int)(60/speed) ,"1" ,-180 ,240 ,speed );
			for(int j=-140;j<-140+w;j+=40){
				addWallData(0 ,"1" ,j ,240 ,speed );
			}
		}
		
	}
	
}

}
public class Stage3:Stage{
	public this(){
		super();
		bg = new Back3();
		
	}
	void setSound(){
		music = music_kind.MUSIC2;
	}
	void setEnemies(){
		
		
		addEnemyData(210 ,"boss3" ,0 ,160 ,0 ,0 ,null ,true);

	}
	
	void setWalls(){
		
	}
	
	void setStars(){
	
	}
	

}

public class Ending:Stage{
	public this(){
		super();
		bg = new Back2();
		
	}
	void setSound(){
		music = -1;
	}
	void setEnemies(){
		

	}
	
	void setWalls(){
		
	}
	
	void setStars(){
	
	}
	

}




