package poly;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;

import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.Relation;
import org.openstreetmap.josm.data.osm.RelationMember;
import org.openstreetmap.josm.data.osm.Way;
import org.openstreetmap.josm.gui.layer.Layer;
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
import org.openstreetmap.josm.io.OsmExporter;

/**
 * Writes poly files.
 * 
 * @author zverik
 */
public class PolyExporter extends OsmExporter {

    public PolyExporter() {
        super(PolyType.FILE_FILTER);
    }

    @Override
    public void exportData( File file, Layer layer ) throws IOException {
        if( layer instanceof OsmDataLayer ) {
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF8"));
            try {
                DataSet ds = ((OsmDataLayer)layer).data;
                Map<Way, Boolean> ways = new TreeMap<>();
                String polygonName = file.getName();
                if( polygonName.indexOf('.') > 0 )
                    polygonName = polygonName.substring(0, polygonName.indexOf('.'));
                for( Way w : ds.getWays() ) {
                    if( w.isClosed() ) {
                        boolean outer = isOuter(w);
                        ways.put(w, outer);
                        if( w.hasKey("name") )
                            polygonName = w.get("name").replace("\n", " ");
                    }
                }
                ways = sortOuterInner(ways);

                int counter = 1;
                writer.write(polygonName);
                writer.newLine();
                for( Way w : ways.keySet() ) {
                    if( !ways.get(w) )
                        writer.write('!');
                    writer.write(String.valueOf(counter++));
                    writer.newLine();
                    for( Node n : w.getNodes() ) {
                        writer.write(String.format(Locale.ENGLISH, "   %f   %f", n.getCoor().lon(), n.getCoor().lat()));
                        writer.newLine();
                    }
                    writer.write("END");
                    writer.newLine();
                }
                writer.write("END");
                writer.newLine();
            } finally {
                writer.close();
            }
        }
    }

    private boolean isOuter( Way w ) {
        for( OsmPrimitive p : w.getReferrers() ) {
            if( p instanceof Relation && ((Relation)p).isMultipolygon() ) {
                for( RelationMember m : ((Relation)p).getMembers() ) {
                    if( m.refersTo(w) && "inner".equals(m.getRole()) ) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    private Map<Way, Boolean> sortOuterInner( Map<Way, Boolean> ways ) {
        LinkedHashMap<Way, Boolean> result = new LinkedHashMap<>(ways.size());
        List<Way> inner = new ArrayList<>();
        for( Way w : ways.keySet() ) {
            Boolean outer = ways.get(w);
            if( outer )
                result.put(w, outer);
            else
                inner.add(w);
        }
        for( Way w : inner )
            result.put(w, Boolean.FALSE);
        return result;
    }
}
