module br.gamemanager;

private import hell2;
private import opengl;
private import SDL;
private import SDL_mixer;
private import std.string;
private import std.math;
private import util.key;
private import util.mouse;
private import util.vector;
private import util.matrix;
private import util.rand;
private import util.collision;
private import util.animation;
private import util.parts;
private import util.particle;
private import util.timer;
private import util.log;
private import util.record;
private import util.ascii;

private import br.shapeImpl;
private import br.particleImpl;
private import br.ship;
private import br.mainloop;
private import br.screen;
private import br.sound;
private import br.frame;
private import br.stage;

private import br.enemy;
private import br.star;
private import br.bullet;
private import br.wall;
private import br.pattern;
private import br.cursor;
private import br.background;
private import br.shot;



public Ship ship;

public Rand rand;
public Screen screen;
public Frame frame;
public Stage stage;
public Cursor cursor;
public BackGround bg;
//public Blast blast;

public PartsManager shipManager;
public PartsManager shotManager;
public PartsManager enemyManager;
public PartsManager starManager;
public PartsManager bulletManager;
public PartsManager wallManager;
public PartsManager patternManager;
public PartsManager cursorManager;
public PartsManager laserManager;


ParticleImplManager particleManager;

public CollisionManager collisionManager;
//public PartsManager appendManager;


private const int MAXSHIP = 10;
private const int DEFAULTSTAGE = 1;
private GameManager gameManager;
private GameState inGameState;
private GameState inTitleState;

private int stageNum;

private int totalTime;
private int lapTime;
private int restShip;
private int _rank;
private double _gameSpeed;
private int _rankpar;
private int _stagenum;

public bool pressingA;

private int[] RANK = 
[0 ,2 ,4 ,6 ,8];

public class GameManager{
	
	public:
	const int SCREEN_WIDTH = 640;
	const int SCREEN_HEIGHT = 480;
	const int SCREEN_BPP = 0;

	/*
	static int g_videoFlags = SDL_SWSURFACE|SDL_OPENGL;
//	const SDL_VideoInfo* info = NULL;
	SDL_Surface *gScreenSurface;
	*/
	
	//int screen_width;
	//int screen_height;
	//int screen_bpp;
	
	static int count;
	private:
	GameState state;
	GameState nextState;
	
	//Parts[10] append;
	
	Key key;
	Mouse mouse;
	
	
	public this(Key key ,Mouse mouse){
		this.key = key;
		this.mouse = mouse;
		gameManager = this;
	}
	public void start(){
		rand = new Rand();
		screen = new Screen();
		
		shipManager = new PartsManager(10);
		shotManager = new PartsManager(128);
		enemyManager = new PartsManager(128);
		starManager = new PartsManager(128);
		bulletManager = new PartsManager(512);
		wallManager = new PartsManager(128);
		patternManager = new PartsManager(512);
		cursorManager = new PartsManager(8);
		laserManager = new PartsManager(8);
		
//		particleManager = new PartsManager(1024);
		
		particleManager = new ParticleImplManager(2048);
//		animationManager = new AnimationManager(64);
		collisionManager = new CollisionManager(1024);
		collisionManager.clear();
		
		Hell_loadTexture("back", "image/back.bmp");
		Hell_loadFont();
		
		Sound_init();
		
		
		inGameState = new InGameState();
		inTitleState = new InTitleState();
		
		reset();
		
		pressingA = true;
		
		state = inTitleState;
		state.start();
		
		nextState = null;
		/*
		if (Mix_PlayMusic(music, -1) != 0) {
			throw new Error("Couldn't play music");
		}
		*/
	}
	public void move(){
		int button = key.getButtonState();
		if(button & key.Button.ENTER)reset();
		
		state.move();

		if(nextState !is null){
			state = nextState;
			
			state.start();
			nextState = null;
		}
		count ++;
		
	}
	public void returnPushed(){
		
		setNextState("game");
		
	}
	public void setNextState(char[] name){
		switch(name){
				case "game":nextState = inGameState;break;
				case "title":nextState = inTitleState;break;
				default:break;
		}
	}
	public void draw(){
//		glClear(GL_DEPTH_BUFFER_BIT);
		state.draw();
	}
	public void reset(){
		clear();
		
		stagenum = 1;
		
		ship = new Ship(key, mouse, 0 ,0);//screen.width / 2,screen.height / 2);
		
		frame = new Frame();
		
		setStage(stagenum);
		
		cursor = new Cursor(mouse);
		
		
		
		count = 0;
		totalTime = 0;
		lapTime = 0;
//		rank = 0;
		rankpar = 0;
		
		
	}
	public void setStage(int s){
		switch(s){
			case 1:stage = new Stage1();break;
			case 2:stage = new Stage2();break;
			case 3:stage = new Stage3();break;
			case 4:stage = new Ending();break;
			default:break;
		}
		bg = stage.bg;
	}
	
	
	
	public void clear(){
		cursorManager.clear();
		shipManager.clear();
		shotManager.clear();
		enemyManager.clear();
		starManager.clear();
		bulletManager.clear();
		wallManager.clear();
		patternManager.clear();
		laserManager.clear();
		
		particleManager.clear();
		collisionManager.clear();
	}
	public void close(){
		clear();
		Sound_free();
		Mix_CloseAudio();
		Hell_disposeTexture();
	}

}

public abstract class GameState{
	protected:
//	bool _end;
	public void start();
	public void move();
	public void draw();
//	public bool end();
	public char[] name();
	
}
public class InGameState:GameState{
	private:

	int count;

	int endCount;
	bool endFlag;
	const char[] _name = "gameState";
	public this(){
	}
	
	public void start(){
		
		count = 0;
		endCount = -1;
		endFlag =false;
		
		
		stage.start();
//		timer = 0;
		
//		_end = false;
	}
	public void move(){
		if(!endFlag){
			if(stage.complete){
				stagenum = stagenum + 1;
				gameManager.setStage(stagenum);
				stage.start();
				enemyManager.allParentsDestroy();
				bulletManager.allParentsDestroy();
				laserManager.allParentsDestroy();
				if(stagenum > 4){
					endCount = 480;
					endFlag = true;
				}
			}
			if(ship.shield < 0){
				endCount = 90;
				endFlag = true;
			}
		}else{
			if(endCount <= 0){
				gameManager.reset();
				gameManager.setNextState("title");
			}
			
			endCount --;
		}
		
		changeRank();
		
		
		cursorManager.move();
		if(ship.shield>=0){
			collisionManager.collisionDetect();
			shipManager.move();
			shotManager.move();
		}
		enemyManager.move();
		starManager.move();
		bulletManager.move();
		laserManager.move();
		wallManager.move();
		patternManager.move();
		
		particleManager.run();
		bg.run();
//		ship.move();
		
		stage.run();
		
		if(rankCount >= 0)rankCount --;
		
		count ++;
		lapTime ++;
		totalTime ++;
		
		
	}
	public void draw(){
			screen.setModelView();
		screen.clear();
		glLoadIdentity();
//		glPushMatrix();
//		screen.setProjection();
	
		//setProjection();
//		drawBackColor(83.0 ,177.0f ,205.0f);

		frame.draw();
		bg.draw();
		
		patternManager.draw();
		
		
		
		
		
		if(ship.shield>=0)shotManager.draw();
		
		laserManager.draw();
		
		particleManager.draw();
		
		glClear(GL_DEPTH_BUFFER_BIT);
		
		if(ship.shield>=0)shipManager.draw();
		
		starManager.draw();
		
		enemyManager.draw();
		
		
		
		wallManager.draw();
		
		glClear(GL_DEPTH_BUFFER_BIT);
		bulletManager.draw();
		
		
		
		
//		glPopMatrix();
//		glPushMatrix();

		glClear(GL_DEPTH_BUFFER_BIT);
		
		cursorManager.draw();
		
		glClear(GL_DEPTH_BUFFER_BIT);
		if(rankCount >= 0){
			if(rankpar >= 50){
				asciiR = 1.0;asciiG = 0.8;asciiB = 0.6;
				drawString("top speed" ,- mulsp(rankCount) * 570.0 /120.0 + 200 ,0,1.5);
				asciiR = 1;asciiG = 1;asciiB = 1;
			}else drawString("speed up" ,- mulsp(rankCount) * 550.0 /120.0 + 200 ,0,1.5);
		}
		if(stagenum > 4 && endCount < 360){
			drawString("thank you" ,-115 ,0,1.0);
			if(endCount < 300){
				if(rankpar >= 50){
					drawString("you are crazy" ,-90 ,-80,0.5);
				}
			}
		}
		
		
		
		screen.setScoreView();
		drawValue(rank ,2 ,20 ,200 ,1.0f);
//		drawValue(rankpar ,3 ,20 ,-20 ,1.0f);
//		drawValue(ship.starnum ,4 ,20 ,220 ,1.0f);
		drawValue(cast(int)fmax(0.0, ship.shield) ,1 ,30 ,-160 ,1.5f);
		drawTimer(count ,10 ,-220 ,0.6);
//		glPopMatrix();
//		ship.draw();

		
		
	}
	
	private void drawBackColor(float R,float G ,float B){
		
		
	}
/*	
	public bool end(){
		return _end;
	}
	*/
	public char[] name(){
		return _name;
	}
}
public class InTitleState:GameState{
	private:

	int count;

	SDL_Surface *back;
	const char[] _name = "titleState";
	public this(){
	}
	
	public void start(){
		
		count = 0;
		back = SDL_LoadBMP( "image/back.bmp" );
		
		Sound_FadeOutMusic(1000);
		
//		timer = 0;
		
//		_end = false;
	}
	public void move(){
		/*
		if(stage.complete){
			stagenum = stagenum + 1;
			gameManager.setStage(stagenum);
		}
		*/
//		changeRank();
		
//		collisionManager.collisionDetect();
		/*
		int button = gameManager.key.getButtonState();
		if(button & Key.Button.A){
			gameManager.reset();
			gameManager.setNextState("game");
		}
		*/
		cursorManager.move();
		shipManager.move();
		shotManager.move();
		enemyManager.move();
		starManager.move();
		bulletManager.move();
		wallManager.move();
//		patternManager.move();
		
		particleManager.run();
		bg.run();
//		ship.move();
		
//		stage.run();
		
		count ++;
		
//		lapTime ++;
//		totalTime ++;
		
		
	}
	public void draw(){
		
			
		
		
			SDL_BlitSurface(back , cast(SDL_Rect*)null ,screen.gScreenSurface ,cast(SDL_Rect*)null);
		
		screen.clear();
		screen.setProjection();
		glLoadIdentity();
		
		Hell_drawTextureEx("back",0,0);
		
		
		screen.setModelView();
		glClear(GL_DEPTH_BUFFER_BIT);
				
//		glPushMatrix();
//		screen.setProjection();
	
		//setProjection();
//		drawBackColor(83.0 ,177.0f ,205.0f);

//		frame.draw();
//		bg.draw();
		
//		patternManager.draw();
		
		
		
		
		
		shotManager.draw();
		
		particleManager.draw();
		
		glClear(GL_DEPTH_BUFFER_BIT);
		
		shipManager.draw();
		
		starManager.draw();
		
		enemyManager.draw();
		
		bulletManager.draw();
		
		wallManager.draw();
		
		
		
		
		
//		glPopMatrix();
//		glPushMatrix();

		glClear(GL_DEPTH_BUFFER_BIT);
		
		cursorManager.draw();
		
		/*
		screen.setScoreView();
		drawValue(rank ,2 ,20 ,120 ,1.0f);
		drawValue(rankpar ,3 ,20 ,-20 ,1.0f);
		drawValue(ship.starnum ,4 ,20 ,220 ,1.0f);
		drawTimer(count ,10 ,-220 ,0.6);
		*/
		
		
//		glPopMatrix();
//		ship.draw();

		
		
		
		
	}
	
	private void drawBackColor(float R,float G ,float B){
		
		
	}
/*	
	public bool end(){
		return _end;
	}
	*/
	public char[] name(){
		return _name;
	}
}


public int rank(){
	return _rank;
}

private void rank(int r){
	if(r<0)_rank = 0;
	else if(r>=50)_rank = 50;//RANK.length)_rank = RANK.length-1;
	else _rank = r;
	gameSpeed = r;
	
}

public double gameSpeed(){
	return _gameSpeed;
}

public void gameSpeed(int rank){
	
//	if(rank <= 0) _gameSpeed = 0.8;
	if(rank < 10)_gameSpeed = 0.9;
	else if(rank < 20)_gameSpeed = 1.0;
	else if(rank < 30)_gameSpeed = 1.1;
	else if(rank < 40)_gameSpeed = 1.2;
	else if(rank < 50)_gameSpeed = 1.3;
	else _gameSpeed = 1.5;
//	if(rank == 50)_gameSpeed = 2.0f;
//	else _gameSpeed = 0.8 + cast(float)rank * 0.02f;

//	_gameSpeed = 1.0f;
	
//	Shot.POWER = 1.0f + fmax(_gameSpeed-1.0f ,0.0f) * 0.5f;
	
//	_gameSpeed = 1.0f;
	/*
	switch(rank){
		case 0:_gameSpeed = 0.8;break;
		case 1:_gameSpeed = 1.0;break;
		case 2:_gameSpeed = 1.2;break;
		case 3:_gameSpeed = 1.5;break;
		case 4:_gameSpeed = 2.0;break;
		default:break;
	}
	*/
}

public double mulsp(double val){
	return val * gameSpeed;
}
public Vector3 mulsp(Vector3 v){
	return v * gameSpeed;
}

public double divsp(double val){
	return val / gameSpeed;
}
public int divsp(int val){
	return cast(int)(cast(double)val / gameSpeed);
}

private int rankCount = -1;

private void changeRank(){
	int n = rankpar;
	rank = 50;//RANK.length - 1;
	for(int i=0;i<=50;i++){
		if(n < i ){
			rank = i-1;
			break;
		}
	}
	
}


public void rankpar(int n){
	
	_rankpar = n;
	if(_rankpar < 0)_rankpar = 0;
	changeRank();
	if(rankpar >= 1 && rankpar % 10 == 0){
		Sound_PlaySe(se_kind.SPEEDUP);
		rankCount = 120;
	}
}

public int rankpar(){
	return _rankpar;
}

public void rankdown(){
	if(rank>0){
		rankpar = 1*(rank-3);//RANK[rank-1];
		changeRank();
	}else rankpar = 0;
}

public void stagenum(int s){
	//if(1<=s&&s<=3)
	_stagenum=s;
}

public int stagenum(){
	return _stagenum;
}