// License: GPL. For details, see LICENSE file.
package jbasemap;

import java.awt.Color;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;

import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;

import render.ChartContext;
import render.Renderer;
import s57.S57map;
import s57.S57map.Feature;
import s57.S57map.GeomIterator;
import s57.S57map.Pflag;
import s57.S57map.Snode;
import s57.S57obj.Obj;
import s57.S57osm;
import symbols.Symbols;

/**
 * @author Malcolm Herring
 */
public final class Jbasemap {
    private Jbasemap() {
        // Hide default constructor for utilities classes
    }

    static String src;
    static String dst;
    static Context context;
    static S57map map;
    static int zoom;
    static double z2;

    static class Context implements ChartContext {

        static double top = 0;
        static double mile = 0;

        Context() {
            top = (1.0 - Math.log(Math.tan(map.bounds.maxlat) + 1.0 / Math.cos(map.bounds.maxlat)) / Math.PI) / 2.0 * 256.0 * z2;
            mile = 256 / ((Math.toDegrees(map.bounds.maxlat) - Math.toDegrees(map.bounds.minlat)) * 60);
        }

        @Override
        public Point2D getPoint(Snode coord) {
            double x = (Math.toDegrees(coord.lon) - Math.toDegrees(map.bounds.minlon)) * 256.0 * (z2 / 2) / 180.0;
            double y = ((1.0 - Math.log(Math.tan(coord.lat) + 1.0 / Math.cos(coord.lat)) / Math.PI) / 2.0 * 256.0 * z2) - top;
            return new Point2D.Double(x, y);
        }

        @Override
        public double mile(Feature feature) {
            return mile;
        }

        @Override
        public int grid() {
            return 0;
        }

        @Override
        public boolean clip() {
            return true;
        }

        @Override
        public Color background(S57map map) {
            if (map.features.containsKey(Obj.COALNE)) {
                for (Feature feature : map.features.get(Obj.COALNE)) {
                    if (feature.geom.prim == Pflag.POINT) {
                        break;
                    }
                    GeomIterator git = map.new GeomIterator(feature.geom);
                    git.nextComp();
                    while (git.hasEdge()) {
                        git.nextEdge();
                        while (git.hasNode()) {
                            Snode node = git.next();
                            if (node == null)
                                continue;
                            if ((node.lat >= map.bounds.minlat) && (node.lat <= map.bounds.maxlat)
                             && (node.lon >= map.bounds.minlon) && (node.lon <= map.bounds.maxlon)) {
                                return Symbols.Bwater;
                            }
                        }
                    }
                }
                return Symbols.Yland;
            } else {
                if (map.features.containsKey(Obj.ROADWY) || map.features.containsKey(Obj.RAILWY) || map.features.containsKey(Obj.LAKARE) ||
                    map.features.containsKey(Obj.RIVERS) || map.features.containsKey(Obj.CANALS)) {
                    return Symbols.Yland;
                } else {
                    return Symbols.Bwater;
                }
            }
        }

        @Override
        public RuleSet ruleset() {
            return RuleSet.BASE;
        }
    }

    public static void main(String[] args) throws IOException {
        if (args.length < 5) {
            System.err.println("Usage: java -jar jbasemap.jar OSM_file SVG_file zoom xtile ytile");
            System.exit(-1);
        }
        src = args[0];
        dst = args[1];
        zoom = Integer.parseInt(args[2]);
        z2 = Math.pow(2, zoom);
        double scale = 0.1;
        File in = new File(src);
        map = new S57map(false);
        try {
            S57osm.OSMmap(in, map, true);
        } catch (Exception e) {
            System.err.println("Input data error");
            System.exit(-1);
        }
        map.bounds.maxlat = Math.atan(Math.sinh(Math.PI * (1 - 2 * Double.parseDouble(args[4]) / z2)));
        map.bounds.minlat = Math.atan(Math.sinh(Math.PI * (1 - 2 * (Double.parseDouble(args[4]) + 1) / z2)));
        map.bounds.minlon = Math.toRadians(Double.parseDouble(args[3]) / z2 * 360.0 - 180.0);
        map.bounds.maxlon = Math.toRadians((Double.parseDouble(args[3]) + 1) / z2 * 360.0 - 180.0);
        context = new Context();
        Rectangle rect = new Rectangle(256, 256);
        DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
        Document document = domImpl.createDocument("http://www.w3.org/2000/svg", "svg", null);
        SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
        svgGenerator.clearRect(rect.x, rect.y, rect.width, rect.height);
        svgGenerator.setSVGCanvasSize(rect.getSize());
        svgGenerator.setClip(rect.x, rect.y, rect.width, rect.height);
        Renderer.reRender(svgGenerator, rect, zoom, scale, map, context);
        svgGenerator.stream(dst);
        System.exit(0);
    }
}
