package org.oscim.theme.carto;

import static java.lang.System.out;
import static org.jeo.map.CartoCSS.BACKGROUND_COLOR;
import static org.jeo.map.CartoCSS.OPACITY;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.jeo.carto.Carto;
import org.jeo.map.CartoCSS;
import org.jeo.map.RGB;
import org.jeo.map.Rule;
import org.jeo.map.RuleList;
import org.jeo.map.Style;
import org.oscim.core.GeometryBuffer.GeometryType;
import org.oscim.core.MapElement;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.theme.IRenderTheme;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.RenderStyle;

public class RenderTheme implements IRenderTheme {

	final String STYLE = "" +

	        "[building = 'yes'] {" +
	        " z: 1;" +
	        "  polygon-fill: #eee;" +
	        "  [zoom >= 16] {" +
	        "    polygon-fill: #c00;" +
	        "  }" +
	        "}" +

	        "[admin_level = '2'] {" +
	        " line-color: #000;" +
	        " line-width: 1;" +
	        " z: 1;" +
	        "}" +

	        "[admin_level = '2'] {" +
	        " line-color: #000;" +
	        " line-width: 1;" +
	        " z: 1;" +
	        "}" +

	        "[admin_level = '4'] {" +
	        " line-color: #aaa;" +
	        " line-width: 1;" +
	        " z: 2;" +
	        "}" +

	        "[highway = 'motorway'] {" +
	        " line-color: #a00;" +
	        " z: 10;" +
	        "}" +

	        "[highway = 'primary'] {" +
	        " line-color: #aa0;" +
	        " z: 11;" +
	        "}" +

	        "[highway = 'residential'],[highway = 'road'],[highway = 'secondary'] {" +
	        " line-color: #fff;" +
	        " z: 12;" +
	        "}" +

	        " [landuse = 'forest'] {" +
	        " polygon-fill: #0a0;" +
	        " z: 2;" +
	        "}" +

	        "[natural = 'water'] {" +
	        " polygon-fill: #00a;" +
	        " z: 3;" +
	        "}";

	private Style mStyle;
	private RuleList mRules;

	MatcherFeature mMatchFeature = new MatcherFeature();
	private int mBackground;

	public RenderTheme() {

		try {
			mStyle = loadStyle();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// get map background
		RuleList rules = mStyle.getRules().selectByName("Map", false);
		if (!rules.isEmpty()) {
			Rule rule = rules.collapse();
			RGB bgColor = rule.color(null, BACKGROUND_COLOR, null);
			if (bgColor != null) {
				bgColor = bgColor.alpha(rule.number(null, OPACITY, 1f));
				mBackground = color(bgColor);
			}
		}

		mRules = mStyle.getRules();

		//out.println(mRules);
		//out.println();
		if (mRules.get(1).equals(mRules.get(2)))
			out.println("ok");

		for (Rule r : mRules)
			out.println(formatRule(r, 0));
	}

	class StyleSet {
		int level;
		RenderStyle[] ri = new RenderStyle[2];
	}

	Map<Rule, StyleSet> mStyleSets = new HashMap<Rule, StyleSet>();
	int mCurLevel = 0;

	public String formatRule(Rule r, int indent) {
		StringBuilder sb = new StringBuilder();

		String pad = "";
		for (int i = 0; i < indent; i++)
			pad += " ";

		sb.append(pad);

		if (sb.length() > 0)
			sb.setLength(sb.length() - 1);

		sb.append(pad).append(" {").append("\n");

		StyleSet s = new StyleSet();
		RGB l = null;
		RGB p = null;
		if (r.properties().containsKey(CartoCSS.LINE_COLOR)) {
			l = r.color(null, CartoCSS.LINE_COLOR, RGB.black);
		}
		if (r.properties().containsKey(CartoCSS.POLYGON_FILL)) {
			p = r.color(null, CartoCSS.POLYGON_FILL, RGB.black);
		}

		if (p != null) {
			s.ri[0] = new AreaStyle(mCurLevel++, color(p));
		}

		if (l != null) {
			s.ri[1] = new LineStyle(mCurLevel++, color(l), 1);
		}

		if (p != null || l != null) {
			mStyleSets.put(r, s);
			out.println("put " + s.ri[0] + s.ri[1]);
		}

		for (Map.Entry<String, Object> e : r.properties().entrySet()) {
			sb.append(pad).append("  ").append(e.getKey()).append(": ").append(e.getValue())
			    .append(";\n");
		}

		for (Rule nested : r.nested()) {
			sb.append(formatRule(nested, indent + 2)).append("\n");
		}

		sb.append(pad).append("}");
		return sb.toString();
	}

	Style loadStyle() throws IOException {
		return Carto.parse(STYLE);
	}

	@Override
	public synchronized RenderStyle[] matchElement(GeometryType type, TagSet tags,
	        int zoomLevel) {
		MatcherFeature f = mMatchFeature;

		f.setTags(tags);
		f.setZoom(zoomLevel);

		RuleList rules = mRules.match(f);

		Rule r = rules.collapse();

		//out.println(r);
		if (rules.isEmpty())
			return null;

		int z = r.number(f, "z", 0f).intValue();

		if (type == GeometryType.POLY) {
			RGB c = r.color(f, CartoCSS.POLYGON_FILL, RGB.black);
			out.println(z + " " + c);
			return new RenderStyle[] {
			        new AreaStyle(z, color(c))
			};

		} else if (type == GeometryType.LINE) {
			RGB c = r.color(f, CartoCSS.LINE_COLOR, RGB.black);
			float width = r.number(f, CartoCSS.LINE_WIDTH, 2f);
			//out.println(z + " " + c);

			return new RenderStyle[] {
			        new LineStyle(100 + z, color(c), width)
			};

		} else if (type == GeometryType.POINT) {
			//RGB c = r.color(f, CartoCSS.MARKER_FILL, RGB.black);
			//out.println(c);
			//return new RenderInstruction[] {
			//		new Caption(color(c), width)
			//};
		}

		return null;
	}

	public static int color(RGB rgb) {
		return rgb.getAlpha() << 24
		        | rgb.getRed() << 16
		        | rgb.getGreen() << 8
		        | rgb.getBlue();
	}

	@Override
	public void destroy() {
	}

	@Override
	public int getLevels() {
		return 1;
	}

	@Override
	public int getMapBackground() {
		return mBackground;
	}

	@Override
	public void scaleTextSize(float scaleFactor) {
	}

	public static void main(String[] args) {
		RenderTheme t = new RenderTheme();

		MapElement e = new MapElement();
		e.startPolygon();
		e.tags.add(new Tag("building", "yes"));

		t.matchElement(GeometryType.POLY, e.tags, 16);
		t.matchElement(GeometryType.POLY, e.tags, 15);
	}

	@Override
	public void updateStyles() {
		// TODO Auto-generated method stub

	}

}