package zero1hd.polyjet.ui.stages;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.utils.viewport.FitViewport;

import zero1hd.polyjet.Polyjet;
import zero1hd.polyjet.audio.map.EntitySpawnInfo;
import zero1hd.polyjet.audio.map.GamePlayMap;
import zero1hd.polyjet.audio.map.MapWindowData;
import zero1hd.polyjet.controls.KeyMap;
import zero1hd.polyjet.entity.CollisionDetector;
import zero1hd.polyjet.entity.Entities;
import zero1hd.polyjet.entity.EntityController;
import zero1hd.polyjet.entity.ally.Laser;
import zero1hd.polyjet.entity.ally.PolyJetEntity;


public class GamePlayArea extends Stage {
	public PolyJetEntity polyjet;
	private GamePlayMap audioMap;
	
	public EntityController ec;
	private CollisionDetector collisionDetector;
	
	private float maxHealth = 100;
	private float yTeleport = Polyjet.GAME_AREA_HEIGHT/2;
	private int score;
	
	private ShaderProgram invert;
	private ShaderProgram bgShader;
	
	private Texture background;
	
	private float time;
	
	public GamePlayArea(AssetManager assetManager, Preferences prefs) {
		super(new FitViewport(Polyjet.GAME_AREA_WIDTH, Polyjet.GAME_AREA_HEIGHT));
		Gdx.app.debug("Game Area", "new area created");
		background = assetManager.get("star_bg.png");
		
		polyjet = new PolyJetEntity(assetManager, 25f, 25f, "standard");
		ec = new EntityController(assetManager);
		collisionDetector = new CollisionDetector(ec.activeAllies, ec.activeEnemies);
		ec.activeAllies.add(polyjet);
		addActor(polyjet);
	}
	
	public void setAudioMap(GamePlayMap audioMap) {
		time = 0;
		this.audioMap = audioMap;
	}
	
	/**
	 * needs to be called right after set as screen (should be called in show method).
	 * @param prefs
	 */
	public void loadShaders(Preferences prefs) {
		if (prefs.getBoolean("invert shader")) {
			Gdx.app.debug("Shader", "using inversion shader");
			invert = new ShaderProgram(Gdx.files.internal("shaders/invert_vert.glsl").readString(), Gdx.files.internal("shaders/invert_frag.glsl").readString());
			ShaderProgram.pedantic = false;
			if (!invert.isCompiled()) {
				System.err.println(invert.getLog());
				System.exit(0);
			}
			if (invert.getLog().length()!=0) {
				System.out.println(invert.getLog());
			}
			getBatch().setShader(invert);
			
		}
		
		if (prefs.getBoolean("bg shader")) {
			Gdx.app.debug("Shader", "using background shader");
			
			bgShader = new ShaderProgram(Gdx.files.internal("shaders/star_vert.glsl").readString(), Gdx.files.internal("shaders/star_frag.glsl").readString());
			
			if (!bgShader.isCompiled()) {
				System.err.println(bgShader.getLog());
				System.exit(0);
			}
			if (bgShader.getLog().length()!=0) {
				System.out.println(bgShader.getLog());
			}
			
		} else {
			//TODO prepare background rendering without shader
		}
		
		ShaderProgram.pedantic = false;
	}
	
	@Override
	public void draw() {
		//TODO batch draw background
		getBatch().begin();
		
		if (bgShader != null) {
			getBatch().setShader(bgShader);
			bgShader.setUniformf("resolution", background.getWidth(), background.getHeight());
			bgShader.setUniformf("time", time);
		}
		getBatch().draw(background, 0f, 0f, Polyjet.GAME_AREA_WIDTH, Polyjet.GAME_AREA_HEIGHT);
		getBatch().end();
		
		
		
		getBatch().setShader(null);
		super.draw();
	}
	
	@Override
	public void act(float delta) {
		MapWindowData mwd;
		if (audioMap != null && audioMap.getPlayableClip().isPlaying() && (mwd = audioMap.nextWindowData()) != null) {
			EntitySpawnInfo[] currentSpawnInfo = mwd.getArray();
			if (currentSpawnInfo != null) {
				for (int i = 0; i < currentSpawnInfo.length; i++) {
					ec.spawnEntity(this, currentSpawnInfo[i]);
				}
			}
		}
		collisionDetector.collisionCheck();
		ec.deathClean();
		
		if (polyjet.getX() <= 1) {
			polyjet.moveLeft = false;
			polyjet.setX(1f);
		}
		
		if (polyjet.getX() >= Polyjet.GAME_AREA_WIDTH-1-polyjet.getWidth()) {
			polyjet.moveRight = false;
			polyjet.setX(Polyjet.GAME_AREA_WIDTH-1f-polyjet.getWidth());
		}
		
		if (polyjet.getY() >= Polyjet.GAME_AREA_HEIGHT - 1 - polyjet.getHeight()) {
			polyjet.moveUp = false;
			polyjet.setY(Polyjet.GAME_AREA_HEIGHT - 1 - polyjet.getHeight());
		}
		
		if (polyjet.getY() <= 1) {
			polyjet.moveDown = false;
			polyjet.setY(1f);
		}
		super.act(delta);
	}
	
	public void addScore (int score) {
		this.score += score;
		polyjet.health += score;
		if (polyjet.health > maxHealth) {
			polyjet.health = maxHealth;
		}
	}

	@Override
	public boolean keyDown(int keycode) {
		if (keycode == KeyMap.left) {
			polyjet.moveLeft = true;
		}
		if (keycode == KeyMap.right) {
			polyjet.moveRight = true;
		}
		
		if (keycode == KeyMap.up) {
			polyjet.moveUp = true;
		}
		
		if (keycode == KeyMap.down) {
			polyjet.moveDown = true;
		}
		
		if (keycode == KeyMap.accelerate) {
			polyjet.accelerate = true;
		}
		return false;
	}
	
	@Override
	public boolean keyUp(int keycode) {
		if (keycode == KeyMap.left) {
			polyjet.moveLeft = false;
		}
		if (keycode == KeyMap.right) {
			polyjet.moveRight = false;
		}
		if (keycode == KeyMap.up) {
			polyjet.moveUp = false;
		}
		if (keycode == KeyMap.down) {
			polyjet.moveDown = false;
		}
		
		if (keycode == KeyMap.accelerate) {
			polyjet.accelerate = false;
		}
		
		if (keycode == KeyMap.shoot) {
			Laser laser	= (Laser) ec.retrieveEntity(Entities.LASER);
			laser.init(polyjet.getX() + (polyjet.getWidth()-laser.getWidth())/2f, polyjet.getY() + polyjet.getHeight()+0.25f, 60f);
			addActor(laser);
		}
		return false;
	}

	public PolyJetEntity getPolyjet() {
		return polyjet;
	}
	
	public int getScore() {
		return score;
	}
	
	public float getMaxHealth() {
		return maxHealth;
	}
	public float getyTeleport() {
		return yTeleport;
	}
	
	@Override
	public void dispose() {
		super.dispose();
	}
}
