package com.custardgames.hotel.states;

import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;

import net.dermetfan.gdx.graphics.g2d.Box2DSprite;
import box2dLight.PointLight;
import box2dLight.RayHandler;

import com.artemis.Entity;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.custardgames.hotel.Core;
import com.custardgames.hotel.entities.ecs.components.Box2dBodyComponent;
import com.custardgames.hotel.entities.ecs.components.Box2dCameraComponent;
import com.custardgames.hotel.entities.ecs.components.Box2dInteractionComponent;
import com.custardgames.hotel.entities.ecs.components.Box2dSpriteComponent;
import com.custardgames.hotel.entities.ecs.components.CameraInputComponent;
import com.custardgames.hotel.entities.ecs.components.CharacterDataComponent;
import com.custardgames.hotel.entities.ecs.components.CharacterInputComponent;
import com.custardgames.hotel.entities.ecs.components.FogComponent;
import com.custardgames.hotel.entities.ecs.components.MusicComponent;
import com.custardgames.hotel.entities.ecs.components.ObjectDataComponent;
import com.custardgames.hotel.entities.ecs.components.ObjectInteractComponent;
import com.custardgames.hotel.entities.ecs.factories.Box2DMapObjectParserFactory;
import com.custardgames.hotel.entities.ecs.systems.Box2dInteractionSystem;
import com.custardgames.hotel.entities.ecs.systems.CameraMovementSystem;
import com.custardgames.hotel.entities.ecs.systems.CharacterInteractSystem;
import com.custardgames.hotel.entities.ecs.systems.CharacterMovementSystem;
import com.custardgames.hotel.entities.ecs.systems.FogSystem;
import com.custardgames.hotel.entities.ecs.systems.MusicSystem;
import com.custardgames.hotel.entities.ecs.systems.ObjectInteractSystem;
import com.custardgames.hotel.entities.ecs.systems.ObjectMovementSystem;
import com.custardgames.hotel.entities.ecs.systems.UpdatePhysicalCharacterInputSystem;
import com.custardgames.hotel.events.PlayerDiedEvent;
import com.custardgames.hotel.handlers.ContactHandler;
import com.custardgames.hotel.managers.EventManager;

public class Play implements Screen, EventListener
{
	private AssetManager assetManager;
	private com.artemis.World artemisWorld;
	private com.badlogic.gdx.physics.box2d.World box2dWorld;
	private ContactHandler contactHandler;

	private boolean reset;

	private OrthographicCamera b2dCam;
	private Box2DDebugRenderer b2dr;

	private TiledMap tileMap1;
	private OrthogonalTiledMapRenderer tmr1;

	private Stage background;
	private Image backgroundImage;
	private RayHandler handler;

	private Music music;

	private SpriteBatch spriteBatch;
	private List<Fixture> b2dPlayerBodies;
	private List<Box2dSpriteComponent> b2dSprites;

	public static final float TICK_STEP = 1 / 60f;
	private float tickCounter;
	private float frameCounter;
	private float secondCounter;

	public Play()
	{
		EventManager.get_instance().register(PlayerDiedEvent.class, this);
		assetManager = new PlayLoadAssets().loadAssets(new AssetManager());
		music = assetManager.get("music/music.mp3");
		music.setLooping(true);
		music.setVolume(1f);
		music.play();
		init();
	}

	public void init()
	{
		reset = false;

		box2dWorld = new com.badlogic.gdx.physics.box2d.World(new Vector2(0f, 0f), true);
		box2dWorld.setContactListener(new ContactHandler());

		contactHandler = new ContactHandler();
		box2dWorld.setContactListener(contactHandler);
		b2dr = new Box2DDebugRenderer();

		artemisWorld = new com.artemis.World();
		artemisWorld.setSystem(new CharacterMovementSystem(assetManager));
		artemisWorld.setSystem(new CameraMovementSystem());
		artemisWorld.setSystem(new UpdatePhysicalCharacterInputSystem());
		artemisWorld.setSystem(new FogSystem());
		artemisWorld.setSystem(new Box2dInteractionSystem());
		artemisWorld.setSystem(new CharacterInteractSystem());
		artemisWorld.setSystem(new ObjectMovementSystem());
		artemisWorld.setSystem(new MusicSystem(music));
		artemisWorld.setSystem(new ObjectInteractSystem(assetManager));

		b2dCam = new OrthographicCamera();
		b2dCam.setToOrtho(false, Core.WIDTH, Core.HEIGHT);
		b2dCam.zoom = 1f;
		b2dCam.update();
		artemisWorld.getSystem(UpdatePhysicalCharacterInputSystem.class).setCamera(b2dCam);

		tileMap1 = new TmxMapLoader().load("maps/world/hotel-horror.tmx");
		Box2DMapObjectParserFactory box2DMapObjectParser = new Box2DMapObjectParserFactory();
		box2DMapObjectParser.load(box2dWorld, tileMap1);

		tmr1 = new OrthogonalTiledMapRenderer(tileMap1, box2DMapObjectParser.getUnitScale());

		spriteBatch = new SpriteBatch();
		spriteBatch.setProjectionMatrix(b2dCam.combined);
		b2dPlayerBodies = new ArrayList<Fixture>();
		b2dSprites = new ArrayList<Box2dSpriteComponent>();

		Fixture radioBody = box2DMapObjectParser.getFixtures().get("radio");
		b2dPlayerBodies.add(radioBody);
		Box2dSpriteComponent radioSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/radio.png"))));
		b2dSprites.add(radioSprite);
		Entity radio = artemisWorld.createEntity();
		radioBody.getBody().setUserData(radio);
		radio.addComponent(new Box2dBodyComponent(radioBody.getBody()));
		radio.addComponent(radioSprite);
		radio.addComponent(new ObjectDataComponent(false));
		radio.addComponent(new ObjectInteractComponent("radio"));
		radio.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("radio-interactive")));
		radio.addToWorld();

		Fixture cakeBody = box2DMapObjectParser.getFixtures().get("cake");
		b2dPlayerBodies.add(cakeBody);
		Box2dSpriteComponent cakeSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/cake.png"))));
		b2dSprites.add(cakeSprite);
		Entity cake = artemisWorld.createEntity();
		cakeBody.getBody().setUserData(cake);
		cake.addComponent(new Box2dBodyComponent(cakeBody.getBody()));
		cake.addComponent(cakeSprite);
		cake.addComponent(new ObjectDataComponent(false));
		cake.addComponent(new ObjectInteractComponent("cake"));
		cake.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("cake-interactive")));
		cake.addToWorld();
		
		Fixture plantBody = box2DMapObjectParser.getFixtures().get("plant");
		b2dPlayerBodies.add(plantBody);
		Box2dSpriteComponent plantSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/plant.png"))));
		b2dSprites.add(plantSprite);
		Entity plant = artemisWorld.createEntity();
		plantBody.getBody().setUserData(plant);
		plant.addComponent(new Box2dBodyComponent(plantBody.getBody()));
		plant.addComponent(plantSprite);
		plant.addComponent(new ObjectDataComponent(false));
		plant.addComponent(new ObjectInteractComponent("plant"));
		plant.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("plant-interactive")));
		plant.addToWorld();
		
		Fixture bedBody = box2DMapObjectParser.getFixtures().get("bed");
		b2dPlayerBodies.add(bedBody);
		Box2dSpriteComponent bedSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/bed.png"))));
		b2dSprites.add(bedSprite);
		Entity bed = artemisWorld.createEntity();
		bedBody.getBody().setUserData(bed);
		bed.addComponent(new Box2dBodyComponent(bedBody.getBody()));
		bed.addComponent(bedSprite);
		bed.addComponent(new ObjectDataComponent(false));
		bed.addComponent(new ObjectInteractComponent("bed"));
		bed.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("bed-interactive")));
		bed.addToWorld();
		
		Fixture pooBody = box2DMapObjectParser.getFixtures().get("poo");
		b2dPlayerBodies.add(pooBody);
		Box2dSpriteComponent pooSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/poo.png"))));
		b2dSprites.add(pooSprite);
		Entity poo = artemisWorld.createEntity();
		pooBody.getBody().setUserData(poo);
		poo.addComponent(new Box2dBodyComponent(pooBody.getBody()));
		poo.addComponent(pooSprite);
		poo.addComponent(new ObjectDataComponent(false));
		poo.addComponent(new ObjectInteractComponent("poo"));
		poo.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("poo-interactive")));
		poo.addToWorld();
		
		Fixture toasterBody = box2DMapObjectParser.getFixtures().get("toaster");
		b2dPlayerBodies.add(toasterBody);
		Box2dSpriteComponent toasterSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/toaster.png"))));
		b2dSprites.add(toasterSprite);
		Entity toaster = artemisWorld.createEntity();
		toasterBody.getBody().setUserData(toaster);
		toaster.addComponent(new Box2dBodyComponent(toasterBody.getBody()));
		toaster.addComponent(toasterSprite);
		toaster.addComponent(new ObjectDataComponent(false));
		toaster.addComponent(new ObjectInteractComponent("toaster"));
		toaster.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("toaster-interactive")));
		toaster.addToWorld();
		
		Fixture plungerBody = box2DMapObjectParser.getFixtures().get("plunger");
		b2dPlayerBodies.add(plungerBody);
		Box2dSpriteComponent plungerSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/plunger.png"))));
		b2dSprites.add(plungerSprite);
		Entity plunger = artemisWorld.createEntity();
		plungerBody.getBody().setUserData(plunger);
		plunger.addComponent(new Box2dBodyComponent(plungerBody.getBody()));
		plunger.addComponent(plungerSprite);
		plunger.addComponent(new ObjectDataComponent(true));
		plunger.addComponent(new ObjectInteractComponent("plunger"));
		plunger.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("plunger-interactive")));
		plunger.addToWorld();
		
		Fixture matchesBody = box2DMapObjectParser.getFixtures().get("matches");
		b2dPlayerBodies.add(matchesBody);
		Box2dSpriteComponent matchesSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/matches.png"))));
		b2dSprites.add(matchesSprite);
		Entity matches = artemisWorld.createEntity();
		matchesBody.getBody().setUserData(matches);
		matches.addComponent(new Box2dBodyComponent(matchesBody.getBody()));
		matches.addComponent(matchesSprite);
		matches.addComponent(new ObjectDataComponent(true));
		matches.addComponent(new ObjectInteractComponent("matches"));
		matches.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("matches-interactive")));
		matches.addToWorld();
		
		Fixture lockeddoorBody = box2DMapObjectParser.getFixtures().get("locked-door");
		b2dPlayerBodies.add(lockeddoorBody);
		Box2dSpriteComponent lockeddoorSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/locked-door.png"))));
		b2dSprites.add(lockeddoorSprite);
		Entity lockeddoor = artemisWorld.createEntity();
		lockeddoorBody.getBody().setUserData(lockeddoor);
		lockeddoor.addComponent(new Box2dBodyComponent(lockeddoorBody.getBody()));
		lockeddoor.addComponent(lockeddoorSprite);
		lockeddoor.addComponent(new ObjectDataComponent(false));
		lockeddoor.addComponent(new ObjectInteractComponent("locked-door"));
		lockeddoor.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("locked-door-interactive")));
		lockeddoor.addToWorld();

		Fixture playerBody = box2DMapObjectParser.getFixtures().get("player");
		b2dPlayerBodies.add(playerBody);
		Box2dSpriteComponent playerSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/player.png"))));
		b2dSprites.add(playerSprite);
		Entity player = artemisWorld.createEntity();
		playerBody.getBody().setUserData(player);
		player.addComponent(new Box2dBodyComponent(playerBody.getBody()));
		player.addComponent(new CharacterInputComponent());
		player.addComponent(new CharacterDataComponent());
		player.addComponent(playerSprite);
		player.addComponent(new Box2dInteractionComponent(box2DMapObjectParser.getFixtures().get("player-interactive")));
		player.addToWorld();
		
		Entity camera = artemisWorld.createEntity();
		camera.addComponent(new Box2dCameraComponent(b2dCam));
		camera.addComponent(new CameraInputComponent(playerBody.getBody()));
		camera.addToWorld();

		int x = 1;
		while (x > 0)
		{

			if (box2DMapObjectParser.getBodies().containsKey("door" + x))
			{
				Fixture doorBody = box2DMapObjectParser.getFixtures().get("door" + x);
				b2dPlayerBodies.add(doorBody);
				Box2dSpriteComponent doorSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/door.png"))));
				b2dSprites.add(doorSprite);
				doorSprite.getSprite().setAlpha(1f);

				Entity doorEntity = artemisWorld.createEntity();
				doorBody.getBody().setUserData(doorEntity);
				doorEntity.addComponent(new Box2dBodyComponent(doorBody.getBody()));
				doorEntity.addComponent(doorSprite);
				doorEntity.addComponent(new FogComponent());
				doorEntity.addToWorld();
				x++;
			}
			else
			{
				x = -1;
			}
		}
		
		
		x = 1;
		while (x > 0)
		{

			if (box2DMapObjectParser.getBodies().containsKey("fog" + x))
			{
				Fixture fogBody = box2DMapObjectParser.getFixtures().get("fog" + x);
				b2dPlayerBodies.add(fogBody);
				Box2dSpriteComponent fogSprite = new Box2dSpriteComponent(new Box2DSprite(new Sprite((Texture) assetManager.get("images/fow.png"))));
				b2dSprites.add(fogSprite);
				fogSprite.getSprite().setAlpha(1f);

				Entity fogEntity = artemisWorld.createEntity();
				if (fogBody.getUserData().equals("jungle"))
				{
					System.out.println("WORKED");
					fogEntity.addComponent(new MusicComponent((Music) assetManager.get("music/music.mp3")));
				}
				fogBody.getBody().setUserData(fogEntity);
				fogEntity.addComponent(new Box2dBodyComponent(fogBody.getBody()));
				fogEntity.addComponent(fogSprite);
				fogEntity.addComponent(new FogComponent());
				fogEntity.addToWorld();
				x++;
			}
			else
			{
				x = -1;
			}
		}

		artemisWorld.initialize();
		handler = new RayHandler(box2dWorld);
		handler.setAmbientLight(0.8f);
		handler.setBlur(true);
		handler.setCulling(true);
		handler.setCombinedMatrix(b2dCam.combined);

		x = 1;
		while (x > 0)
		{

			if (box2DMapObjectParser.getBodies().containsKey("light" + x))
			{
				new PointLight(handler, 100, new Color(1, 1, 1, 0.5f), 10, 0, 0).attachToBody(box2DMapObjectParser.getBodies().get("light" + x), 0, 0);
				x++;
			}
			else
			{
				x = -1;
			}
		}

		PointLight.setContactFilter((short) 19, (short) 0, (short) 19);

		background = new Stage();
		background.getViewport().setWorldSize(1280, 720);
		backgroundImage = new Image((Texture) assetManager.get("images/background.png"));
		backgroundImage.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		background.addActor(backgroundImage);
	}

	@Override
	public void render(float delta)
	{
		tickCounter += Gdx.graphics.getDeltaTime();
		while (tickCounter >= TICK_STEP)
		{
			tickCounter -= TICK_STEP;
			update(TICK_STEP);
		}

		render();
		frameCounter++;

		if (secondCounter > 1)
		{
			System.out.println("Frames Per Second: " + frameCounter);
			secondCounter--;
			frameCounter = 0;
		}
		secondCounter += Gdx.graphics.getDeltaTime();
	}

	@Override
	public void resize(int width, int height)
	{
		spriteBatch.setProjectionMatrix(b2dCam.combined);
		handler.setCombinedMatrix(b2dCam.combined);
	}

	@Override
	public void show()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void hide()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void pause()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void resume()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void dispose()
	{
		box2dWorld.dispose();
		assetManager.dispose();
		music.dispose();
	}

	public void update(float dt)
	{
		box2dWorld.step(dt, 6, 2);
		artemisWorld.setDelta(dt);
		artemisWorld.process();
		handler.update();

		if (reset == true)
		{
			reset = false;
			init();
		}
	}

	public void render()
	{
		Gdx.gl.glClearColor(0, 0, 0, 1);
		Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);

		background.draw();

		tmr1.setView(b2dCam);
		tmr1.render();

		spriteBatch.setProjectionMatrix(b2dCam.combined);
		spriteBatch.begin();
		for (int x = 0; x < b2dPlayerBodies.size(); x++)
		{
			b2dSprites.get(x).getSprite().draw(spriteBatch, b2dPlayerBodies.get(x));
		}
		spriteBatch.end();

		handler.setCombinedMatrix(b2dCam.combined);
		handler.render();

		// b2dr.render(box2dWorld, b2dCam.combined);

	}

	public void handlePlayerDiedEvent(PlayerDiedEvent e)
	{
		reset = true;
	}
}
