package uk.co.beercave.gunboat.renderers;

import java.util.Comparator;

import uk.co.beercave.gunboat.ResourceManager;
import uk.co.beercave.gunboat.entities.GameObject;
import uk.co.beercave.gunboat.entities.GameWorld;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.Pool;
import com.badlogic.gdx.utils.Pool.Poolable;

public class SeaRenderer {

	private static SeaRenderer instance;
	private OrthographicCamera camera;
	private SpriteBatch batch;
	private float time;
	
	private Pool<Renderable> renderablePool;
	public class Renderable implements Poolable{
		public GameObject parent;

		public Renderable(){
			reset();
		}
		public Color color;
		public TextureRegion tx;
		public float scale;
		public float rotation;
		@Override
		public void reset() {
			parent = null;
			scale = 1;
			rotation = 0;
			tx = null;
		}
	}
	public static Renderable newSprite(){
//		Gdx.app.log("RENDERER", "Acquiring sprite");
//		Gdx.app.log("RENDERER", "Renderable count before : " + new Float(instance.renderables.size).toString());		
		Renderable r =instance.renderablePool.obtain();
		instance.renderables.add(r);
//		Gdx.app.log("RENDERER", "Renderable count after : " + new Float(instance.renderables.size).toString());

//		new Exception().printStackTrace();
		return r;
	};
	//horrible hack to get the bullets to always be in front of the waves
	public static Renderable newFrontSprite(){
		Renderable r =instance.renderablePool.obtain();
		instance.frontRenderables.add(r);
		return r;
	};
	public static void releaseSprite(Renderable sprite){
//		Gdx.app.log("RENDERER", "Releasing sprite");
//		Gdx.app.log("RENDERER", "Renderable count before : " + new Float(instance.renderables.size).toString());		
		instance.renderables.removeValue(sprite, true);
		instance.renderablePool.free(sprite);
//		Gdx.app.log("RENDERER", "Renderable count after : " + new Float(instance.renderables.size).toString());

	}
	public static void releaseFrontSprite(Renderable sprite){
		instance.frontRenderables.removeValue(sprite, true);
		instance.renderablePool.free(sprite);
	}
	private Array<Renderable> renderables;
	private Array<Renderable> frontRenderables;
	private float ZMap[];
	private SeaRenderer(){
		renderablePool = new Pool<SeaRenderer.Renderable>(){

			@Override
			protected Renderable newObject() {
				return new Renderable();
			}
			
		};
		ZMap = new float[10];
		for(int i=0; i<10; i++){
			ZMap[i] = 1f/(i+1);
			int capacity = (int) (20 / ZMap[i]);
			//Gdx.app.log("", "Wave " + new Integer(i).toString() + " capacity " + new Integer(capacity).toString());
		}
		
		time = 0;
		seaColor = new Color();
		renderables = new Array<SeaRenderer.Renderable>();
		frontRenderables = new Array<SeaRenderer.Renderable>();
		//generate some random boats
//		for(int i=0; i< 20; i++){
//			Renderable boat = new Renderable();
//			boat.x = MathUtils.random(800);
//			boat.y = 0;
//			boat.z = MathUtils.random(1,9);
//			boat.color = boatColors.random();
//			boat.tx = ResourceManager.boat;
//			//Gdx.app.log("", "Boat at " + new Float(boat.x).toString() + ", " + new Float(boat.z).toString());
//			boats.add(boat);
//		}
		
	}
	
	public static void initialise(OrthographicCamera camera, SpriteBatch batch) {
		if (instance == null) instance = new SeaRenderer();
		instance.camera = camera;
		instance.batch = batch;
		
	}
	
	public static void render(float delta){
		instance.renderSea(delta);
	}
	
	private Color seaColor;
	private Comparator<SeaRenderer.Renderable> renderComparator = new Comparator<SeaRenderer.Renderable>() {
		
		@Override
		public int compare(Renderable b0, Renderable b1) {
			return (int) (b1.parent.z - b0.parent.z);
		}
	};
	private void renderSea(float delta){
		time += delta;
		//ok, just to get things moving, let's have a row of blocks at Z=1
		float y = 200;
		batch.begin();
		seaColor.set(.2f, .3f, 1, 1);
		
		renderables.sort(renderComparator);
		frontRenderables.sort(renderComparator);
		
		int currentBoat = 0;
		for(int z = 9/*Change to 9 when we're drawing the rest of the waves*/; z>= 0; z--){
			//Gdx.app.log("",  "Z= " + new Float(z).toString());
			float width = Math.max(2,ZMap[z]*800/40);
			//Gdx.app.log("", "Block width " + new Float(width).toString());
			
			batch.setColor(1,1,1,1);
			//now draw all the boats at this level
			//Gdx.app.log("",  "renderables : " + new Float(z).toString());
			while(currentBoat < renderables.size){
				Renderable b = renderables.get(currentBoat);
				if (b.parent.z <= z-1) {

					//Gdx.app.log("",  "Skipping Boat Z= " + new Float(b.parent.z).toString());
					break;
				};
				//Gdx.app.log("",  "Drawing Boat Z= " + new Float(b.z).toString());
				currentBoat++;
				float boatx = b.parent.x;
				float yOffset = 0;
				float zScale = 1f/(b.parent.z+1);
				if (b.parent.floating){
					yOffset = 18*ZMap[z]* (MathUtils.sinDeg(y+ boatx *1.5f+time*(100+z*10)*ZMap[z])+.5f);
				}
				float boaty = y+100 + yOffset;
				//adjust for this z line
				//boatx *= ZMap[z];
				//boatx += 400-400*ZMap[z];
				float spriteWidth = b.tx.getRegionWidth()*b.scale;
				float spriteHeight = b.tx.getRegionHeight()*b.scale;
				batch.setColor(b.color);
				//Gdx.app.log("", "Boat at " + new Float(b.parent.x).toString() + ", " + new Float(b.parent.z).toString());	
				float w2 = spriteWidth/2*ZMap[z];
				float h2 = spriteHeight/2*ZMap[z];

				batch.draw(b.tx, 
						boatx-w2,
						boaty-h2, 
						w2, h2,
						spriteWidth*ZMap[z], 
						spriteHeight*ZMap[z],
						1, 1, 
						b.rotation
								
						);
			}
			float x = 0;
			batch.setColor(seaColor);
			while(x < 800){
				
				float blockOffset = 20*ZMap[z] * MathUtils.sinDeg(y+ x*1.5f+time*(100+z*10)*ZMap[z]);// wave.get(i) * ZMap[z];
				batch.draw(ResourceManager.blankTx, x, y+blockOffset, width, 100);
				x += width;
			}
			seaColor.r -= seaColor.r*.2f;
			seaColor.g -= seaColor.g*.2f;
			y -= ZMap[z] * 80;
		}
		currentBoat = 0;
		y = 200;
		float lastY = 200;
		for(int z = 9/*Change to 9 when we're drawing the rest of the waves*/; z>= 0; z--){
			//Gdx.app.log("",  "Z= " + new Float(z).toString());
			float width = Math.max(2,ZMap[z]*800/40);while(currentBoat < frontRenderables.size){
				Renderable b = frontRenderables.get(currentBoat);
				if (b.parent.z <= z-1) {

					//Gdx.app.log("",  "Skipping Boat Z= " + new Float(b.parent.z).toString());
					break;
				};
				//Gdx.app.log("",  "Drawing Boat Z= " + new Float(b.z).toString());
				currentBoat++;
				float boatx = b.parent.x;
				float yOffset = 0;
				float zScale = 1f/(b.parent.z+1);
				//Gdx.app.log("", "Bullet Z = " + new Float(b.parent.z).toString() + ", zScale = " + new Float(zScale).toString());
				float boaty = y+100 + yOffset;
				
				//if Z is not exact, lerp from last y position
				float remainder = b.parent.z - (int)b.parent.z;
				//Gdx.app.log("", "Remainder = " + new Float(remainder).toString());
				float diff = (y - lastY) * remainder;
				boaty -= diff;
				float spriteWidth = b.tx.getRegionWidth()*b.scale;
				float spriteHeight = b.tx.getRegionHeight()*b.scale;
				batch.setColor(b.color);
				//Gdx.app.log("", "Bullet at " + new Float(b.parent.x).toString() + ", " 
				//		+ new Float(b.parent.z).toString() + ", " + new Float(boaty).toString());
				batch.draw(b.tx, boatx-spriteWidth/2*ZMap[z],boaty, spriteWidth*ZMap[z], spriteHeight*ZMap[z]);

			}
			lastY = y;
			y -= ZMap[z] * 80;			
		}
			
		batch.setColor(.4f, .45f, .4f, 1);
		batch.draw(ResourceManager.blankTx, 0, 0, 800, 100);
		batch.setColor(.2f, .25f, .2f, 1);
		batch.draw(ResourceManager.blankTx, 0, 60, 800, 10);
		batch.draw(ResourceManager.blankTx, 0, 30, 800, 10);
		
		float gunx = GameWorld.player.x;
		batch.setColor(1,1,1,1);
		batch.draw(ResourceManager.gun, gunx-64, 10);
		batch.end();
	}
}
