/*
 * Copyright (C) 2008 Steve Ratcliffe
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 * 
 * Author: Steve Ratcliffe
 * Create date: 10-Dec-2008
 */
package uk.me.parabola.mkgmap.osmstyle;

import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import uk.me.parabola.imgfmt.app.Coord;
import uk.me.parabola.mkgmap.general.LineAdder;
import uk.me.parabola.mkgmap.general.MapLine;
import uk.me.parabola.mkgmap.scan.SyntaxException;
import uk.me.parabola.mkgmap.scan.TokenScanner;

/**
 * Reads the overlay file.
 * There are not many line types available in the version of the .img
 * format that we are using, but you can simulate more by clever use
 * of TYP files and overlaying lines on top of each other.
 *
 * The format of the file is just a series of lines that start with
 * the fake type and followed by a list of types that will actually
 * be created.
 *
 * Eg.
 * 0x123: 0x12, 0x14, 0x15
 *
 * If a rule results in the type 0x123 (which wouldn't normally show up)
 * it is replaced by three lines with the type 0x12, 0x14, 0x15.
 *
 * @author Steve Ratcliffe
 * @see <a href="TODO: find url">Example of the technique</a>
 *
 */
public class OverlayReader {
	private final Map<Integer, List<Integer>> overlays = new HashMap<Integer, List<Integer>>();
	private final Reader reader;
	private final String filename;

	public OverlayReader(Reader r, String filename) {
		reader = r;
		this.filename = filename;
	}

	public void readOverlays() {
		TokenScanner ts = new TokenScanner(filename, reader);
		while (!ts.isEndOfFile()) {
			String line = ts.readLine();

			// Remove comments before parsing
			int commentstart = line.indexOf("#");
			if (commentstart != -1)
				line = line.substring(0, commentstart);

			String[] fields = line.split(":", 2);
			if (fields.length == 2) {
				try {
					overlays.put(Integer.decode(fields[0]), readReplacements(ts, fields[1]));
				} catch (NumberFormatException e) {
					throw new SyntaxException(ts, "Expecting a number");
				}
			}
		}
	}

	/**
	 * Read the line of replacements.
	 */
	private List<Integer> readReplacements(TokenScanner ts, String line) {
		List<Integer> l = new ArrayList<Integer>();

		String[] nums = line.split("[ ,]");
		for (String n : nums) {
			if (n == null || n.length() == 0) 
				continue;

			try {
				l.add(Integer.decode(n));
			} catch (NumberFormatException e) {
				throw new SyntaxException(ts, "List of numbers expected");
			}
		}

		return l;
	}

	public void addLine(MapLine line, LineAdder adder) {
		int origType = line.getType();
		List<Integer> integerList = overlays.get(origType);
		if (integerList != null) {
			MapLine newline = line.copy();
			newline.setType(integerList.get(0));
			List<Coord> points = line.getPoints();
			newline.setPoints(points);
			adder.add(newline);

			// Force all following types to be added as lines rather than roads.
			for (ListIterator<Integer> t=integerList.listIterator(1); t.hasNext(); ) {
				newline = new MapLine(line);
				newline.setType(t.next());
				newline.setPoints(new ArrayList<Coord>(points));
				adder.add(newline);
			}
		} else {
			adder.add(line);
		}
	}

	public Map<Integer, List<Integer>> getOverlays() {
		return overlays;
	}
	

}
