package CreateGridOfWaysPlugin;

import static org.openstreetmap.josm.tools.I18n.tr;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Collection;
import java.util.LinkedList;

import javax.swing.JOptionPane;

import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.JosmAction;
import org.openstreetmap.josm.command.AddCommand;
import org.openstreetmap.josm.command.Command;
import org.openstreetmap.josm.command.SequenceCommand;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.Way;
import org.openstreetmap.josm.tools.Shortcut;

/**
 * Crea una grilla de vías usando como base las dos seleccionadas que tengan un nodo en común
 * y probablemente sean perpendiculares entre si , deben tener ambas vías un nodo en cada esquina
 * (Please if you understand this translate to English)
 *
 * @author Jorge Luis Chamorro
 */
@SuppressWarnings("serial")
public final class CreateGridOfWaysAction extends JosmAction {

    public CreateGridOfWaysAction() {
        super(tr("Create grid of ways"), "creategridofways", tr("Forms a grid of ways in base to two existing that have various nodes and one in common"), Shortcut.registerShortcut("tools:CreateGridOfWays", tr("Tool: {0}", tr("Create grid of ways")),
        KeyEvent.VK_G, Shortcut.SHIFT), true);
    }

    /**
     * Dadas 2 vias seleccionadas buscamos el punto en comun entre ambas y luego las recorremos para crear una grilla
     * de vias paralelas a esas dos creando los nodos que son sus puntos de union y reusando los existentes
     * (Please if you understand this translate to English)
     * They given 2 ways selected we seek the point in common between both and then we travel through them to
     * create a grid of ways parallel to those creating the nodes that are its points of union and reusing the
     * existing ones (--this is from a translation machine--)
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        Collection<OsmPrimitive> sel = Main.main.getCurrentDataSet().getSelected();
        Collection<Node> nodesWay1 = new LinkedList<>();
        Collection<Node> nodesWay2 = new LinkedList<>();
        if ((sel.size() != 2) || !(sel.toArray()[0] instanceof Way) || !(sel.toArray()[1] instanceof Way)) {
            JOptionPane.showMessageDialog(Main.parent, tr("Select two ways with a node in common"));
            return;
        }
        nodesWay1.addAll(((Way)sel.toArray()[0]).getNodes());
        nodesWay2.addAll(((Way)sel.toArray()[1]).getNodes());
        Node nodeCommon = null;
        for (Node n : nodesWay1)
            for (Node m : nodesWay2)
                if (n.equals(m)) {
                    if ( nodeCommon != null ) {
                        JOptionPane.showMessageDialog(Main.parent, tr("Select two ways with alone a node in common"));
                        return;
                    }
                    nodeCommon = n;
                }
        Way w2[] = new Way[nodesWay2.size()-1];
        for (int c=0;c<w2.length;c++)
            w2[c]=new Way();
        Way w1[] = new Way[nodesWay1.size()-1];
        for (int c=0;c<w1.length;c++)
            w1[c]=new Way();
        Collection<Command> cmds = new LinkedList<>();
        int c1=0,c2;
        double latDif,lonDif;
        for (Node n1 : nodesWay1) {
            latDif = n1.getCoor().lat()-nodeCommon.getCoor().lat();
            lonDif = n1.getCoor().lon()-nodeCommon.getCoor().lon();
            c2=0;
            for (Node n2 : nodesWay2) {
                if (n1.equals(nodeCommon) && n2.equals(nodeCommon))
                    continue;
                if (n2.equals(nodeCommon)) {
                    w1[c1].addNode(n1);
                    continue;
                }
                if (n1.equals(nodeCommon)) {
                    w2[c2++].addNode(n2);
                    continue;
                }
                Node nodeOfGrid = new Node(new LatLon(n2.getCoor().lat()+latDif,n2.getCoor().lon()+lonDif));
                cmds.add(new AddCommand(nodeOfGrid));
                w1[c1].addNode(nodeOfGrid);
                w2[c2++].addNode(nodeOfGrid);
            }
            if (!n1.equals(nodeCommon))
               c1++;
        }
        for (int c=0;c<w1.length;c++)
            cmds.add(new AddCommand(w1[c]));
        for (int c=0;c<w2.length;c++)
            cmds.add(new AddCommand(w2[c]));
        Main.main.undoRedo.add(new SequenceCommand(tr("Create a grid of ways"), cmds));
        Main.map.repaint();
    }
}
