package org.nusco.narjillos.views;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.effect.BoxBlur;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.effect.Effect;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;

import org.nusco.narjillos.pond.Pond;
import org.nusco.narjillos.pond.PondEventListener;
import org.nusco.narjillos.shared.things.Thing;

public class PondView {

	private final Pond pond;
	private final Viewport viewport;
	private final Shape background;
	private final Map<Thing, ThingView> thingsToViews = new HashMap<>();

	private boolean infrared = false;

	public PondView(Pond pond) {
		this.pond = pond;
		viewport = new Viewport(pond);
		background = new Rectangle(0, 0, pond.getSize(), pond.getSize());

		for (Thing thing : pond.getThings())
			addThingView(thing);

		pond.addEventListener(new PondEventListener() {
			@Override
			public void thingAdded(Thing thing) {
				addThingView(thing);
			}

			@Override
			public void thingRemoved(Thing thing) {
				removeThingView(thing);
			}
		});
	}

	public Viewport getViewport() {
		return viewport;
	}

	public Node toNode() {
		Group result = new Group();
		result.getChildren().add(getBackground(isInfrared()));
		result.getChildren().add(getThingsGroup(isInfrared()));
		return result;
	}

	private Group getThingsGroup(boolean infraredOn) {
		Group things = new Group();
		things.getChildren().addAll(getNodesForThings(infraredOn));

		things.getTransforms().add(new Translate(-viewport.getPositionPC().x, -viewport.getPositionPC().y));
		things.getTransforms().add(new Scale(viewport.getZoomLevel(), viewport.getZoomLevel(),
											viewport.getPositionPC().x, viewport.getPositionPC().y));

		setZoomLevelEffects(things);
		
		return things;
	}

	private void setZoomLevelEffects(Group group) {
		double zoomLevel = viewport.getZoomLevel();
		
		if (zoomLevel <= 1)
			return;
		
		group.setEffect(getBlurEffect(zoomLevel));
	}

	private Shape getBackground(boolean infraredOn) {
		if (infraredOn) {
			background.setFill(Color.DARKGRAY.darker());
			return background;
		}

		background.setFill(Color.ANTIQUEWHITE);
		double brightnessAdjust = -viewport.getZoomLevel() / 5;
		background.setEffect(new ColorAdjust(0, 0, brightnessAdjust, 0));
		return background;
	}
	
	private List<Node> getNodesForThings(boolean infraredOn) {
		List<Node> result = new LinkedList<>();
		for (ThingView view : getThingViews()) {
			Node node = view.toNode(viewport, infraredOn);
			if (node != null)
				result.add(node);
		}
		return result;
	}

	private Effect getBlurEffect(double zoomLevel) {
		int blurAmount = (int)(15 * (zoomLevel - 1));
		return new BoxBlur(blurAmount, blurAmount, 1);
	}

	private synchronized Collection<ThingView> getThingViews() {
		return new HashSet<ThingView>(thingsToViews.values());
	}

	private synchronized ThingView addThingView(Thing thing) {
		return thingsToViews.put(thing, ThingView.createViewFor(thing));
	}

	private synchronized void removeThingView(Thing thing) {
		thingsToViews.remove(thing);
	}

	public void tick() {
		viewport.tick();
	}

	public Pond getPond() {
		return pond;
	}

	public synchronized void toggleInfrared() {
		infrared = !infrared;
	}

	private synchronized boolean isInfrared() {
		return infrared;
	}
}

@@ -2931,17 +2931,19 @@
 Level - 
-1
+0.7
 ));%0A%09%09re

Tweak overzooming blur effect