package lighting;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.image.BufferedImage;
import java.util.ConcurrentModificationException;

import engine.Camera;
import engine.Game;
import engine.Handler;
import hud.Clock;
import hud.Clock.TIME;
import interfaces.ItemIDs;
import player.Player;
import utils.Point2f;
import utils.Stack;
import utils.Utils;

/*  ------------- Nihilne ------------
    * Created by Mitch Weaver - 2016 *
      ~~~~ All Rights Reserved ~~~~ */

public final class RadialLight implements ItemIDs {
	
	public final static Stack<RadialLight> lights = new Stack<RadialLight>();
	public final int radius;
	public Point2f center;
	public final BufferedImage lightImage;
	
	private static BufferedImage lightmap = new BufferedImage(Game.WIDTH, Game.HEIGHT, BufferedImage.TYPE_INT_ARGB);
	
	public RadialLight(final Point2f center, final int radius, final float intensity){
		this.center = center; this.radius = radius; 
		Color[] color = { new Color(0, 0, 0, intensity), new Color(0, 0, 0, 0) };
		lightImage = new BufferedImage(radius * 2, radius * 2, BufferedImage.TYPE_INT_ARGB);
		Graphics2D g2d = (Graphics2D) lightImage.getGraphics();
		
		float[] distance = { 0f, 1f };
		g2d.setPaint(new RadialGradientPaint(new Point(radius, radius), radius, distance, color));
		g2d.fillOval(0, 0, radius * 2, radius * 2);
		g2d.dispose();
	}
	
	private final void update(Graphics2D lightsRenderer){
		lightsRenderer.drawImage(lightImage.getScaledInstance((int)(lightImage.getWidth() * Game.scaleFactor),
		(int)(lightImage.getHeight() * Game.scaleFactor), Image.SCALE_FAST),
		(int)((center.x + Camera.x) * Game.scaleFactor) - (int)(radius * Game.scaleFactor), 
		(int)((center.y + Camera.y) * Game.scaleFactor) - (int)(radius * Game.scaleFactor), null);
	}
	
	private static int alternate, darkness, hue;
	private static float temp;
	private static final int RED_AMOUNT = 65, GREEN_AMOUNT = 10;
	public static final void render(final Graphics2D g2d){
		// DONT RENDER LIGHTS IF IT IS DAY
		if(Clock.clock == TIME.DAY) return;
		
		// ONLY UPDATE THE EVERY OTHER FRAME, HELPS REDUCE LAG
		if(alternate <= 0){ alternate++; /* draw the update all the lights every other frame to reduce lag, not very noticeable */
		
		lightmap = new BufferedImage((int) (Game.game.getWidth() * 1.1), (int) (Game.game.getHeight() * 1.1), BufferedImage.TYPE_INT_ARGB);
		
		Graphics2D lightsRenderer = (Graphics2D) lightmap.getGraphics();
		
		if (Clock.clock == TIME.DAWN){
			temp = ((((float)(Clock.DAY - Clock.time)) / (Clock.DAY)));
			
			darkness = (int)(temp*254);
			if(darkness < 0) darkness = 0;
			else if(darkness > 254) darkness = 242;
			
			if(temp < 0.5f) hue = (int)(temp * GREEN_AMOUNT);
			else hue = GREEN_AMOUNT - (int)(temp * GREEN_AMOUNT);
			
			lightsRenderer.setColor(new Color(hue/3, hue, 0, darkness));
			
		} else if (Clock.clock == TIME.DUSK){
			temp = ((((float)(Clock.time - Clock.DUSK)) / (Clock.NIGHT - Clock.DUSK)));
			
			darkness = (int)(temp*255);
			if(darkness < 0) darkness = 0; 
			else if(darkness > 255) darkness = 255;
			
			if(temp < 0.5f) hue = (int)(temp * RED_AMOUNT);
			else hue = RED_AMOUNT - (int)(temp * RED_AMOUNT);
			
			lightsRenderer.setColor(new Color(hue, 0, 0, darkness));
		} else if (Clock.clock == TIME.NIGHT)lightsRenderer.setColor(Color.black);
		
		lightsRenderer.fillRect(0, 0, lightmap.getWidth(), lightmap.getHeight());
		lightsRenderer.setComposite(AlphaComposite.DstOut);
		lightsRenderer.rotate((Game.rotation - 1) * Utils._45);
		
		try{ for(final RadialLight light : lights) if(Handler.AREA_RECT.contains(light.center.x, light.center.y)) light.update(lightsRenderer); }
		catch (ConcurrentModificationException cme){ /* happens when adding / removing lights, ignore */ }
		
		try{ for(final RadialLight playerLight : Player.playerLights) if(Handler.AREA_RECT.contains(playerLight.center.x, playerLight.center.y)) playerLight.update(lightsRenderer); }
		catch (ConcurrentModificationException cme){ /* happens when adding / removing lights, ignore */ }
		
		lightsRenderer.dispose();
		} else { alternate--; }
		
		g2d.drawImage(lightmap, 0, 0, null);
	}
	
	public static final void determineLight(final int itemId){
		switch(itemId){
			case TORCH: if(!Player.playerLights.contains(Player.torchLight)) Player.playerLights.add(Player.torchLight); break;
		}
	}
	
	public static final void removeLight(final int itemId){
		switch(itemId){
			case TORCH: if(Player.playerLights.contains(Player.torchLight)) Player.playerLights.remove(Player.torchLight); break;
		}
	}
	
}
