package;

import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.text.FlxText;
import flixel.util.FlxMath;
import flixel.util.FlxColor;
import flixel.group.*;
import flixel.util.FlxCollision;
import flixel.util.FlxTimer;
import flixel.util.FlxRandom;
import flixel.util.FlxPoint;
import flixel.tweens.FlxTween;
import flixel.tweens.FlxEase;
import flixel.input.keyboard.FlxKey;

/**
 * A FlxState which can be used for the actual gameplay.
 */
class PlayState extends FlxState
{

	private var players = new FlxTypedGroup<Player>();
	private var walls = new FlxTypedGroup<FlxSprite>();
	private var keys_used = new Map<String, Player>();
	var wall_top:FlxSprite;
	var wall_bottom:FlxSprite;
	var wall_middle:FlxSprite;
	var wall_height:Float;
	var wall_height_min:Int = 100;
	var wall_height_max:Int = 100;
	var wall_time:Float = 6.0;
	var outline:FlxSprite;
	var pose:Int;
	var pose_max:Float = 0.0;
	var floor:FlxSprite;
	var hole_size:Float;
	var hole_size_min:Int = 600;
	var hole_size_max:Int = 600;
	var players_can_join = true;
	var how_to_play:FlxSprite;
	var round_num = 1;
	var round_text:FlxText;

	/**
	 * Function that is called up when to state is created to set it up. 
	 */
	override public function create():Void
	{
		// Camera bg colour
		FlxG.camera.bgColor = 0xFF73c6b0;						
		
		// Fade in		
		FlxG.camera.fade(0xFF73c6b0, .2, true);

		// Walls
		wall_middle = new FlxSprite( 0, 0 );
		wall_middle.makeGraphic( 50, FlxG.height, 0xFF79b4a4 );
		wall_middle.alpha = 0;
		add(wall_middle);

		wall_bottom = new FlxSprite( 0, 0 );
		wall_bottom.makeGraphic( 50, FlxG.height, 0xFF5b103c );
		wall_bottom.alpha = 0;
		walls.add(wall_bottom);		

		wall_top = new FlxSprite( 0, 0 );
		wall_top.makeGraphic( 50, FlxG.height, 0xFF5b103c );
		wall_top.alpha = 0;
		walls.add(wall_top);	
		add(walls);		

		// Round text
		round_text = new FlxText( 0, FlxG.height / 2.5, FlxG.width );
		round_text.setFormat("assets/GOTHIC.TTF", 150, 0x5b103c, "center");
		round_text.alpha = 0;
		add(round_text);

		// Outline
		outline = new FlxSprite( 0, 0 );
		outline.loadGraphic(Reg.assets_dir + "player_outline.png", true, 50, 50);
		outline.animation.add("pose0", [0]);
		outline.animation.add("pose1", [1]);
		outline.animation.add("pose2", [2]);
		outline.animation.add("pose3", [3]);
		outline.alpha = 0;	
		add(outline);		

		//Floor
		floor = new FlxSprite( 0, FlxG.height - 50 );
		floor.makeGraphic( FlxG.width, 50, 0xFF73c7b1 );
		floor.immovable = true;
		add(floor);		

		// Players
		add(players);

		// How to play image
		how_to_play = new FlxSprite( 0, 0 );
		how_to_play.loadGraphic(Reg.assets_dir + "how_to_play.png");
		how_to_play.x = FlxG.width / 2 - how_to_play.width / 2;
		how_to_play.y = FlxG.height / 2 - how_to_play.height / 2;
		add(how_to_play);

		super.create();				
	}

	private function next_round()
	{		

		// Round text		
		round_text.text = "" + round_num;
		round_text.alpha = 1;
		FlxTween.tween(round_text, { alpha:0 }, 1.5, { ease: FlxEase.quadInOut });
		round_num++;


		// var player = players.getFirstDead();
		//  if (player != null)
		// {			
		// 	player.revive();
		// }		

		//update_walls();
		wall_bottom.alpha = 1;
		wall_top.alpha = 1;
		wall_middle.alpha = 1;
		outline.alpha = 1;

		var startX:Float;
		var startY:Float;
		if (wall_bottom.x < FlxG.width / 2) {			
			startX = FlxG.width - 50;
		}
		else 		
		{
			startX = 0;				
		}
		FlxTween.tween(wall_bottom, { x:startX }, wall_time, { ease: FlxEase.quadInOut, complete: wall_stop });
		FlxTween.tween(wall_top, { x:startX }, wall_time, { ease: FlxEase.quadInOut });		
		FlxTween.tween(wall_middle, { x:startX }, wall_time, { ease: FlxEase.quadInOut });		
		FlxTween.tween(outline, { x:startX }, wall_time, { ease: FlxEase.quadInOut });	
	}

	private function wall_stop(tween:FlxTween)
	{
		//new FlxTimer(10.0, wall_start, 3);
		if (hole_size_min > 150)
		{
			hole_size_min -= 50;
		}

		if (wall_height_min < 200)
		{
			wall_height_min += 25;
		}

		if (wall_height_max < 400)
		{
			wall_height_max += 50;
		}

		if (wall_time > 2)
		{
			wall_time -= 0.5;
		}

		if (pose_max < 3) 
		{
			pose_max += 1;
		}

		update_walls();

		var timer = new FlxTimer(0.5, timer_complete);		
	}

	private function timer_complete(timer:FlxTimer)
	{
		next_round();
	}

	private function update_walls()
	{
		wall_height = FlxRandom.intRanged( wall_height_min, wall_height_max );
		hole_size = FlxRandom.intRanged( hole_size_min, hole_size_max );

		pose = FlxRandom.intRanged( 0, Math.floor(pose_max) );
		outline.animation.play( "pose" + pose );
		
		align_walls();
	}

	private function align_walls ()
	{
		var bottomY = FlxG.height - wall_height;
		var topY = wall_bottom.y - FlxG.height - hole_size;
		var outlineY = (bottomY - (hole_size / 2));


		FlxTween.tween(wall_bottom, { y:bottomY }, 0.2, { ease: FlxEase.quadInOut});
		FlxTween.tween(wall_top, { y:topY }, 0.2, { ease: FlxEase.quadInOut});
		FlxTween.tween(outline, { y:outlineY }, 0.2, { ease: FlxEase.quadInOut});
	}

	private function add_player(key:String)
	{
		if (players_can_join) 
		{	
			// Text
			var keyText = new FlxText( 0, FlxG.height - 50, 50 ); // x, y, width
			keyText.text = key;
			keyText.setFormat("assets/GOTHIC.TTF", 20, 0x5b103c, "center");
			add(keyText);

			// Player
			var player = new Player( 0, FlxG.height - 105, keyText );		
			players.add(player);

			// Realign players
			align_players();

			// Store player reference
			keys_used[key] = player;
		}

	}

	private function add_corpse (X:Float, Y:Float, pose:Int, yVelocity:Float)
	{
		var corpse:FlxSprite = new FlxSprite( X, Y );
		corpse.loadGraphic(Reg.assets_dir + "player_dead.png", true, 50, 50);
		corpse.animation.add("pose0", [2]);
		corpse.animation.add("pose1", [3]);
		corpse.animation.add("pose2", [4]);
		corpse.animation.add("pose3", [5]);

		corpse.animation.play("pose" + Math.max(pose, 0));
		var xSpeed = Math.random() * 500 + 500;
		if (wall_top.x + wall_top.width / 2 > X) {
			xSpeed = -xSpeed;
		}
		corpse.velocity.x = xSpeed;
		corpse.angularVelocity = Math.random() * 100 - 50;
		corpse.velocity.y = yVelocity - 500;
		corpse.acceleration.y = 2000;

		add(corpse);
	}

	private function align_players()
	{
		var gapSize:Float = 20;
		var xPos:Float = FlxG.width / 2 - ((players.length * 50 ) / 2) - (players.length * gapSize / 2);
		for (player in players) 
		{			
			player.x = xPos;
			player.keyText.x = xPos;
			xPos += gapSize + 50;
		}
	}

	/**
	 * Function that is called when this state is destroyed - you might want to 
	 * consider setting all objects this state uses to null to help garbage collection.
	 */
	override public function destroy():Void
	{
		super.destroy();
	}

	/**
	 * Function that is called once every frame.
	 */
	override public function update():Void
	{

		// Start game check
		if (players_can_join && players.length > 0) {
			var all_players_ready = true;
			for (player in players)
			{
				if (player.pose != 1)
				all_players_ready = false;
				//break;
			}

			if (all_players_ready) {
				players_can_join = false;
				how_to_play.kill();
				update_walls();
				next_round();
			}
		}

		// End game check
		if (!players_can_join && players.getFirstAlive() == null) {			
			endGame();
		}

		// Reset player inputs
		for (player in players)
		{
			if (player.key_is_down) {
				player.key_was_down = true;
			}
			player.key_is_down = false;
		}

		// Keyboard input
		var keys = FlxG.keys.getIsDown();
		for (key in keys) 
		{
			var keycode = FlxG.keys.getKeyCode( key.name );
			if (FlxG.keys.checkStatus( keycode, 1 )) {
				if (!keys_used.exists(key.name)) 
				{
					add_player( key.name );
				}
				else {
					var player = keys_used.get(key.name);
					player.key_down();
					// charge player
				}
			}
		}

		// Player collisions
		FlxG.collide( players, floor, player_touch_floor );
		FlxG.overlap(walls, players, wall_touch_player);

		// Check pose
		FlxG.overlap(players, wall_middle, player_touch_gate);

		super.update();
	}

	private function kill_player(player:Player)
	{
		player.kill();

		add_corpse(player.x, player.y, player.pose, player.velocity.y);			

		var timer = new Respawn( Math.ceil(player.keyText.x), Math.ceil(player.keyText.y), wall_time * 2 + wall_time / 2, player );
		add(timer);
	}

	private function player_touch_gate(player:Player, wall_middle:FlxSprite)
	{
		if (player.pose == pose) {
			player.touch();
		}
		else {
			kill_player(player);			
		}
	}

	private function player_touch_floor(player:Player, floor:FlxSprite)
	{
		player.landed();
	}

	private function wall_touch_player(wall:FlxSprite, player:Player)
	{
		//players.remove( player );
		kill_player(player);		
		//align_players();
	}

	public function endGame() 
	{			
		FlxG.camera.fade(0xFF73c6b0, 0.5, false, function() {
			var endState = new MainMenuState();
        	FlxG.switchState(endState);
		});
	}
}