package de.fhpotsdam.unfolding.ui;

import java.util.Arrays;
import java.util.List;

import processing.core.PApplet;
import processing.core.PFont;
import de.fhpotsdam.unfolding.UnfoldingMap;
import de.fhpotsdam.unfolding.geo.Location;
import de.fhpotsdam.unfolding.utils.GeoUtils;
import de.fhpotsdam.unfolding.utils.ScreenPosition;

public class BarScaleUI {
	private static final List<Float> DISPLAY_DISTANCES = Arrays.asList(
			0.01f, 0.02f, 0.05f, 0.1f, 0.2f, 0.5f, 1f, 2f,
			5f, 10f, 20f, 50f, 100f, 200f, 500f, 1000f, 2000f, 5000f);

	private static final float MAX_DISPLAY_DISTANCE = 5000;

	private boolean autoAlignment = true;

	// If false it uses the screen center, resulting in a bar scale depending on
	// the north/south position of the map.
	boolean showDistanceAtEquator = false;

	private PApplet p;
	private UnfoldingMap map;
	public float x;
	public float y;

	// style:
	private int color;
	private int barWeight;
	private int barCapOffset;

	public BarScaleUI(PApplet p, UnfoldingMap map, float x, float y) {
		this.p = p;
		this.map = map;
		this.x = x;
		this.y = y;

		barWeight = 1;
		barCapOffset = 0;
		p.color(255);
		p.textFont(p.createFont("Sans-Serif", 10));

	}

	public BarScaleUI(PApplet p, UnfoldingMap map) {
		this(p, map, 20, map.mapDisplay.getHeight() - 20);
	}

	/**
	 * Draws a bar scale at given position according to current zoom level.
	 * 
	 * Calculates distance at equator (scale is dependent on Latitude). Uses a
	 * distance to display from fixed set of distance numbers, so length of bar
	 * may vary.
	 */
	public void draw() {
		// Distance in km, appropriate to current zoom
		float distance = MAX_DISPLAY_DISTANCE / map.getZoom();
		distance = getClosestDistance(distance);

		Location startLocation = null;
		Location destLocation = null;
		if (showDistanceAtEquator) {
			// Get destLocation (world center, on equator, with calculated distance)
			startLocation = new Location(0, 0);
			destLocation = GeoUtils.getDestinationLocation(startLocation, 90f, distance);
		} else {
			startLocation = map.getLocation(p.width / 2, p.height / 2);
			destLocation = GeoUtils.getDestinationLocation(startLocation, 90f, distance);
		}
		// Calculate distance between both locations in screen coordinates
		ScreenPosition destPos = map.getScreenPosition(destLocation);
		ScreenPosition startPos = map.getScreenPosition(startLocation);
		float dx = destPos.x - startPos.x;

		// Display
		p.fill(color);
		if (autoAlignment && x > map.mapDisplay.getWidth() / 2) {
			dx *= -1;
			p.text(PApplet.nfs(distance, 0, 0) + " km", x + 3, y + 4);
		} else {
			p.text(PApplet.nfs(distance, 0, 0) + " km", x + dx + 3, y + 4);
		}
		p.stroke(color);
		p.strokeWeight(barWeight);
		p.line(x - .5f, y, x + .5f + dx, y);
		p.strokeWeight(1);

		int capHeightUp = (barCapOffset == 0) ? 3 : (barCapOffset > 0) ? 0 : -barCapOffset;
		int capHeightDown = (barCapOffset == 0) ? 3 : (barCapOffset < 0) ? 0 : barCapOffset;
		capHeightUp += barWeight / 2;
		capHeightDown += barWeight / 2;

		p.line(x, y - capHeightUp, x, y + capHeightDown);
		p.line(x + dx, y - capHeightUp, x + dx, y + capHeightDown);

	}

	public void setStyle(int color, int barWeight, int barCapOffset, PFont font) {
		this.color = color;
		this.barWeight = barWeight;
		this.barCapOffset = barCapOffset;
		p.textFont(font);
	}

	/**
	 * Returns the nearest distance to display as well as to use for
	 * calculation.
	 * 
	 * @param distance
	 *            The original distance
	 * @return A distance from the set of {@link DISPLAY_DISTANCES}
	 */
	protected float getClosestDistance(float distance) {
		return closest(distance, DISPLAY_DISTANCES);
	}

	protected float closest(float of, List<Float> in) {
		float min = Float.MAX_VALUE;
		float closest = of;

		for (float v : in) {
			final float diff = Math.abs(v - of);

			if (diff < min) {
				min = diff;
				closest = v;
			}
		}
		return closest;
	}
}

@@ -1186,17 +1186,16 @@
 , 10));%0A
-%0A
 %09%7D%0A%0A%09pub
@@ -3515,16 +3515,17 @@
  %7B@link 
+#
 DISPLAY_

Fix broken javadoc link.