package uk.co.beercave.gunboat.renderers;

import uk.co.beercave.gunboat.ResourceManager;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.Mesh.VertexDataType;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.IntArray;

public class SkyRenderer {

	private static SkyRenderer instance;
	private OrthographicCamera camera;
	private SpriteBatch batch;
	private float time;
	private Mesh mesh;
	private static ShaderProgram shader;
	
	private Array<Cloud> clouds;
	private class Fragment{
		public Rectangle rect;
		public Color color;
		public Fragment(){
			rect = new Rectangle();
			rect.x = MathUtils.random(-100,100);
			rect.y = MathUtils.random(-50,50);
			rect.width = MathUtils.random(20, 40);
			rect.height = MathUtils.random(10, 30);
			float c = MathUtils.random(.8f, 1);
			color = new Color(c,c,c,MathUtils.random(.4f, .6f));
		}
	}
	private class Cloud{
		public Array<Fragment> fragments;
		public Vector2 position;
		public float speed;
		public Cloud(int fragCount){
			fragments = new Array<SkyRenderer.Fragment>(fragCount);
			position = new Vector2(MathUtils.random(800), MathUtils.random(300,400));
			speed = MathUtils.random(1f,4f) * (MathUtils.randomBoolean()?-1:1);
			for(int i=0; i<fragCount; i++){
				fragments.add(new Fragment());
			}
		}
	}
	
	public static void initialise(OrthographicCamera camera, SpriteBatch batch) {
		if (instance == null) instance = new SkyRenderer();
		instance.camera = camera;
		instance.batch = batch;

		if (Gdx.graphics.isGL20Available()) {
			shader = batch.createDefaultShader();
		}
		//initialise sun ray mesh
		Color rayColor = new Color();
		rayColor.set(255*1f/255, 182*1f/255, 31*1f/255, .5f);
		
		FloatArray verts = new FloatArray();
		IntArray idcs = new IntArray();
		
		int idx = 0;
		int sunx = 800;
		int suny = 480;
		for(int t = 0; t < 150; t+= 20){
			verts.add(sunx);
			verts.add(suny);
			verts.add(0);
			verts.add(rayColor.toFloatBits());
			idcs.add(idx++);
			
			float x = sunx-1000*MathUtils.cosDeg(t);
			float y = suny-1000*MathUtils.sinDeg(t);
			verts.add(x);
			verts.add(y);
			verts.add(0);
			verts.add(rayColor.toFloatBits());
			idcs.add(idx++);
			
			x = sunx-1000*MathUtils.cosDeg(t+10);
			y = suny-1000*MathUtils.sinDeg(t+10);
			verts.add(x);
			verts.add(y);
			verts.add(0);
			verts.add(rayColor.toFloatBits());
			idcs.add(idx++);
		}
		instance.mesh = new Mesh(true, verts.size, idcs.size, 
	            new VertexAttribute(Usage.Position, 3, "a_position"),
	            new VertexAttribute(Usage.ColorPacked, 4, "a_color"));
		instance.mesh.setVertices(verts.items);
		short[] shortIdcs = new short[idcs.size];
		for(int i=0; i<idcs.size; i++){
			shortIdcs[i] = (short) idcs.get(i);
		}
		instance.mesh.setIndices(shortIdcs);
		instance.clouds = new Array<Cloud>();
		for(int i=0; i<MathUtils.random(3,8); i++){
			instance.clouds.add(instance.new Cloud(MathUtils.random(20,35)));
		}
	}
	
	public static void render(float delta){
		instance.renderSky(delta);
	}

	private Color skyColor = new Color();
	private Color sunColor = new Color();
	private void renderSky(float delta) {
		time += delta;
		batch.begin();
		skyColor.set(55*1f/255, 93*1f/255, 1, 1);
		//step 1 - draw some sky
		float top = 480;
		float height = 60;

		while (height > 1){
			batch.setColor(skyColor);
			batch.draw(ResourceManager.blankTx, 0, top-height, 800, height);
			skyColor.r += (1-skyColor.r)*.25f;
			skyColor.g += (1-skyColor.g)*.25f;
			skyColor.b += (1-skyColor.b)*.25f;
			top -= height;
			height *= .75f;
		}
		
		//rays
		batch.end();

		Gdx.gl.glEnable(GL20.GL_BLEND);
		Gdx.gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		if (Gdx.graphics.isGL20Available()) {
			shader.begin();
			mesh.render(shader, GL10.GL_TRIANGLES);
			shader.end();
		} else {
			mesh.render(GL10.GL_TRIANGLES);
		}
		//mesh.render(GL10.GL_TRIANGLES);
		
		batch.begin();
		//sun
		sunColor.set(251*1f/255, 255*1f/255, 45*1f/255, .4f);
		batch.setColor(sunColor);

		//enable additive blend
		//batch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
		batch.enableBlending();
		float x = 750;
		float y = 430;
		float width = 50;
		height = 50;
		float offset1 = 10 * MathUtils.sin(time);
		float offset2 = 10 * MathUtils.sin(time+2);
		batch.draw(ResourceManager.blankTx, x - offset1, y - offset1, width + offset1*2, height + offset1*2);
		batch.draw(ResourceManager.blankTx, x - offset2, y - offset2, width + offset2*2, height + offset2*2);
		
		sunColor.a = 1;

		batch.setColor(sunColor);
		batch.draw(ResourceManager.blankTx, x, y, width, height);
		
		//disable additive blend
		//batch.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		
		//do clouds live here?
		for(int i=0; i<clouds.size; i++){
			Cloud c = clouds.get(i);
			for(int j=0; j<c.fragments.size; j++){
				Fragment f = c.fragments.get(j);
				batch.setColor(f.color);
				batch.draw(ResourceManager.blankTx, c.position.x + f.rect.x, c.position.y + f.rect.height, f.rect.width, f.rect.height);
			}
			c.position.x += c.speed * delta;
			if (c.position.x < -200){
				c.position.x = 1000;
			}else if (c.position.x > 1000){
				c.position.x = -200;
			}
		}
		
		batch.setColor(Color.WHITE);
		batch.end();
	}

}
