package game;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServlet;

import account.Account;
import framework.gameMain.OvergroundActor;
import framework.model3D.CollisionResult;
import framework.model3D.Object3D;
import framework.model3D.Position3D;
import framework.model3D.Universe;
import framework.physics.Ground;
import framework.physics.PhysicsUtility;
import framework.physics.Velocity3D;
import java3d.Vector3d;
import room.Room;

public class Game implements IGameElement {
	
	public static final int TEAM_RED = 0;
	public static final int TEAM_BLUE = 1;
	
	private Room room = null;
	private Team teamRed = new Team();
	private Team teamBlue = new Team();
	
	private Stage stage = new Stage();
	
	public static final int GAME_TIME = 180000;			//3m 180000ms
	public static final int COOL_TIME = 10000; 			//10s 10000ms
	public static final int LASER_ACTIVE_TIME = 20000;	//20s 20000ms
	public static final int MIRROR_ACTIVE_TIME = 20000;	//20s 20000ms
	
	int remainTime = 180000;//残り時間
	
	int startTime = 0;
	
	boolean removeFlag = false;
	
	//pre:準備中　play:ゲーム中　red,blue:勝利チーム　end:制限時間終了
	String state = "pre";
	
	private Universe universe = new Universe();
	
	CollisionResult cr = null;
	
	/*******************************
	 *	update
	 *******************************/
	public void update(int countTime) {

		/*------------------------------
		 	state = pre 待機中
		 ------------------------------*/
		if(state.equals("pre")) {
			state = "play";
			startTime = countTime;
		
			
		/*------------------------------
	 	state = play ゲーム中
	 	 ------------------------------*/
		} else if(state.equals("play")) {
	
			//残り時間
			remainTime = GAME_TIME - calcElapsedTime(countTime, startTime);
			
			//ゲーム進行判定　残り時間があるかどうか
			if(remainTime <= 0) {
				state = "end";
				return;
			}
			
			//Laserのクールタイムの確認
			if(teamRed.getCoolTimeFlag() == true) {
				//経過時間
				if(COOL_TIME <= calcElapsedTime(countTime, teamRed.getCoolTime())) {
					teamRed.setCoolTimeFlag(false);
				}
			}
			
			//teamRedのLaserTurert・Mirrorの消失判定
			LaserTurretActiveCheck(teamRed, countTime);
			MirrorActiveCheck(teamRed, countTime);
			
			//teamBlueのLaserTurert・Mirrorの消失判定
			LaserTurretActiveCheck(teamBlue, countTime);
			MirrorActiveCheck(teamBlue, countTime);
			
			//アイテムを動かす
			universe.update(GameManager.DELAY_TIME);
			
			//Laserと壁が当たった時のLaser消失処理　各チーム毎
			if(teamRed.getLaserTurret() != null && teamRed.getLaserTurret().getLaser() != null && teamRed.getLaserTurret().getLaser().getIsCollision()) {
				universe.displace(teamRed.getLaserTurret().getLaser());
				teamRed.removeLaserTurret(countTime);
			}
			if(teamBlue.getLaserTurret() != null && teamBlue.getLaserTurret().getLaser() != null &&teamBlue.getLaserTurret().getLaser().getIsCollision()) {
				universe.displace(teamBlue.getLaserTurret().getLaser());
				teamBlue.removeLaserTurret(countTime);
			}
					
			//爆弾の処理・鏡,ステージとのあたり判定含む
			
			//teamRedのレーザのあたり判定
			if(teamRed.getLaserTurret() != null) {
				//　仮仕様でstateがonでもcompでもあたり判定する　本来はonのみ
				if((teamRed.getLaserTurret().getState().equals("comp")) || (teamRed.getLaserTurret().getState().equals("on"))) {

					//Laserを取得
					Laser laserR = teamRed.getLaserTurret().getLaser();
					
					//laserR　と　teamRedの全鏡のあたり判定　反射
					LaserMirrorCheckCollision(laserR, teamRed);
					
					//laserR と teamBlueの全鏡のあたり判定　反射
					LaserMirrorCheckCollision(laserR, teamBlue);
					
					//laserR と 全プレイヤのあたり判定
					LaserPlayerCheckCollision(laserR);
				}
			}
			
			//teamBlueのレーザのあたり判定
			if(teamBlue.getLaserTurret() != null) {
				//　仮仕様でstateがonでもcompでもあたり判定する
				if((teamBlue.getLaserTurret().getState().equals("comp")) || (teamBlue.getLaserTurret().getState().equals("on"))) {
				
					//Laserを取得
					Laser laserB = teamBlue.getLaserTurret().getLaser();
					
					//laserB　と　teamRedの全ての鏡のあたり判定　反射
					LaserMirrorCheckCollision(laserB, teamRed);
					
					//laserB　と　teamBlueの全ての鏡のあたり判定　反射
					LaserMirrorCheckCollision(laserB, teamBlue);
					
					//レーザ光線とプレイヤ全員のあたり判定
					LaserPlayerCheckCollision(laserB);
				}
			}
		/*------------------------------
		 state = end, red, blue　ゲーム終了
		 ------------------------------*/
		} else if(state.equals("end") || state.equals("red") || state.equals("blue")) {
System.out.println("end　か　red か　blue　の else if");
			gameRemoveCheck(countTime);
		}
	}
	
	//赤・青チームにアカウントを追加し、アカウントにも登録する
	public void setTeamTo(Account ac, int team) {
		if(team == TEAM_RED) {
			teamRed.addMember(ac);
		} else if(team == TEAM_BLUE) {
			teamBlue.addMember(ac);
		}
		
		//アカウントに登録
		ac.setTeam(team);
	}
	
	//赤・青チームのn番目のメンバーを返す
	public Account getTeamMember(int n,int team) {
		if(team == TEAM_RED){
			return teamRed.getMember(n);
		}else if(team == TEAM_BLUE){
			return teamBlue.getMember(n);
		}
		
		return null;
	}
	
	//自分以外の赤・青チームのn番目のメンバーを返す
	public Account getTeamMemberExceptSelf(int n,int team,String sId) {
		if(team == TEAM_RED){
			Account ac = teamRed.getMember(n);
			if(!ac.getsId().equals(sId)){
				return ac;
			}
		}else if(team == TEAM_BLUE){
			Account ac = teamBlue.getMember(n);
			if(!ac.getsId().equals(sId)){
				return ac;
			}
		}
		
		return null;
	}
	
	//レーザを配置する
	public void placeLaser(Laser laser) {
		universe.place(laser);
	}
	
	//Mirrorを配置する
	public void placeMirror(Mirror mirror) {
		universe.place(mirror);
	}
	
	//ステージを配置する
	public void placeStage() {
		final Ground ground = new StageStandard();
		universe.place(ground);
	}
	
	//経過時間の計算　　countTime = 現在時間、 time =　ゲームのスタート時間やアイテムの設置時間など
	public int calcElapsedTime(int countTime, int startTime) {
		return (countTime - startTime) * GameManager.DELAY_TIME;
	}
	
	//残り時間
	public int remainTime() {
		int rTime = remainTime / 1000; 
		return rTime;
	}
	
	//LaserTurretの有効判定
	public void LaserTurretActiveCheck(Team team, int countTime) {
		if(team.getLaserTurret() != null) {
			
			//Laserを持っているのに、startTimeが記録されていなければ記録する。
			if(team.getLaserTurret().getLaser() != null && team.getLaserTurret().getStartTime() == 0) {
				team.getLaserTurret().setStartTime(countTime);
				
			//Laserを持っていて、startTimeが記録されているときは経過時間の判定
			} else if(team.getLaserTurret().getLaser() != null && team.getLaserTurret().getStartTime() != 0) {

				//経過時間を判定し、規定時間以上の場合は消失
				if(LASER_ACTIVE_TIME <= calcElapsedTime(countTime, team.getLaserTurret().getStartTime())) {
					universe.displace(team.getLaserTurret().getLaser());
					team.removeLaserTurret(countTime);
				}
			}
		}
	}
	
	//Mirrorの有効判定
	public void MirrorActiveCheck(Team team, int countTime) {
		for(int i=0; i<team.countMirror(); i++) {
			Mirror mirror = team.getMirror(i);
			
			//startTimeが記録されていない場合は記録
			if(mirror.getStartTime() == 0) {
				mirror.setStartTime(countTime);
				
			//startTimeが記録されている場合は経過時間の判定
			} else if(MIRROR_ACTIVE_TIME <= calcElapsedTime(countTime,mirror.getStartTime())) {
				universe.displace(mirror);
				team.removeMirror(mirror);
			}
		}
	}
	
	//LaserとMirrorのあたり判定
	public void LaserMirrorCheckCollision(Laser laser, Team team) {
		for(int i=0; i<team.countMirror(); i++) {
			Mirror mirror = team.getMirror(i);
			cr = null;
			if(( cr = PhysicsUtility.checkCollision((Object3D)mirror.getBody(), null, (Object3D)laser.getBody(), null)) != null) {
				Vector3d v = laser.calcReflection(cr.normal);
				Velocity3D v2 = new Velocity3D(v);
				laser.setVelocity(v2);
				break;
			}
		}	
	}
	
	//LaserとPlayerのあたり判定
	public void LaserPlayerCheckCollision(Laser laser) {
		for(int i=0; i<room.getMemberCount(); i++) {
			cr = null;
			Player player = room.getMember(i).getPlayer();
System.out.println("Collision check: player(" + player.getPointX() + ","  + player.getPointY() + "," + player.getPointZ() + "), laser(" +  + laser.getX() + ","  + laser.getY() + "," + laser.getZ() + ")");
			if((cr = PhysicsUtility.checkCollision((Object3D)player.getBody(), null, (Object3D)laser.getBody(), null)) != null) {
System.out.println("Game sethit");
				player.setHit("laser");
			}
		}
	}
	
	//Gameの消去判定　ゲーム終了から5s経過でremoveFlagをtrue
	public void gameRemoveCheck(int countTime) {
		//ゲームが終了してから5000ms(5s)以上経った場合
System.out.println("gameRemoveCheck: in");
		if(5000 <= calcElapsedTime(countTime, startTime) - GAME_TIME) {
System.out.println("gameRemoveCheck: if");
			removeFlag = true;
		}
	}
	
	//roomをセットする
	public void setRoom(Room room) {
		this.room = room;
	}
	public Room getRoom() {
		return room;
	}
	
	//部屋名を返す
	public String getRoomName() {
		return room.getName();
	}
	
	//team
	public Team getTeamRed() {
		return teamRed;
	}
	public Team getTeamBlue() {
		return teamBlue;
	}
	
	//stage
	public Stage getStage() {
		return stage;
	}
	
	//state
	public String getState() {
		return state;
	}
	public void setState(String state) {
		this.state = state;
	}
	
	//sTime
	public void setStartTime(int count) {
		this.startTime = count;
	}
	
	//gameFlag
	public boolean getRemoveFlag() {
		return removeFlag;
	}
	
	//visitorによる処理を受け入れる
	public boolean accept(IGameElementVisitor v) {
		if(!v.visit(this)) return false;
		if (!teamRed.accept(v)) return false;
		if (!teamBlue.accept(v)) return false;
		return true;
	}
}