// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.public_transport.models;

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

import java.util.Vector;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.Way;
import org.openstreetmap.josm.plugins.public_transport.actions.RoutePatternAction;

public class ItineraryTableModel extends DefaultTableModel implements TableModelListener {
    public Vector<Way> ways = new Vector<>();

    public boolean inEvent = false;

    @Override
    public boolean isCellEditable(int row, int column) {
        if (column != 1)
            return false;
        if (ways.elementAt(row) == null)
            return false;
        return true;
    }

    @Override
    public void addRow(Object[] obj) {
        ways.addElement(null);
        super.addRow(obj);
    }

    @Override
    public void insertRow(int insPos, Object[] obj) {
        if (insPos == -1) {
            ways.addElement(null);
            super.addRow(obj);
        } else {
            ways.insertElementAt(null, insPos);
            super.insertRow(insPos, obj);
        }
    }

    public void addRow(Way way, String role) {
        insertRow(-1, way, role);
    }

    public void insertRow(int insPos, Way way, String role) {
        String[] buf = {"", ""};
        String curName = way.get("name");
        if (way.isIncomplete())
            buf[0] = tr("[incomplete]");
        else if (way.getNodesCount() < 1)
            buf[0] = tr("[empty way]");
        else if (curName != null)
            buf[0] = curName;
        else
            buf[0] = tr("[ID] {0}", Long.valueOf(way.getId()));
        buf[1] = role;
        if (insPos == -1) {
            ways.addElement(way);
            super.addRow(buf);
        } else {
            ways.insertElementAt(way, insPos);
            super.insertRow(insPos, buf);
        }
    }

    public void clear() {
        ways.clear();
        super.setRowCount(0);
    }

    public void cleanupGaps() {
        inEvent = true;
        Node lastNode = null;

        for (int i = 0; i < getRowCount(); ++i) {
            if (ways.elementAt(i) == null) {
                ++i;
                if (i >= getRowCount())
                    break;
            }
            while ((ways.elementAt(i) == null) && ((i == 0) || (ways.elementAt(i - 1) == null))) {
                ways.removeElementAt(i);
                removeRow(i);
                if (i >= getRowCount())
                    break;
            }
            if (i >= getRowCount())
                break;

            boolean gapRequired = gapNecessary(ways.elementAt(i), (String) getValueAt(i, 1),
                    lastNode);
            if (i > 0 && !gapRequired && ways.elementAt(i - 1) == null) {
                ways.removeElementAt(i - 1);
                removeRow(i - 1);
                --i;
            } else if (i > 0 && gapRequired && ways.elementAt(i - 1) != null) {
                String[] buf = {"", ""};
                buf[0] = tr("[gap]");
                insertRow(i, buf);
                ++i;
            }
            lastNode = getLastNode(ways.elementAt(i), (String) getValueAt(i, 1));
        }
        while (getRowCount() > 0 && ways.elementAt(getRowCount() - 1) == null) {
            ways.removeElementAt(getRowCount() - 1);
            removeRow(getRowCount() - 1);
        }
        inEvent = false;
    }

    @Override
    public void tableChanged(TableModelEvent e) {
        if (e.getType() == TableModelEvent.UPDATE) {
            if (inEvent)
                return;
            cleanupGaps();
            RoutePatternAction.rebuildWays();
        }
    }

    private Node getLastNode(Way way, String role) {
        if (way == null || way.isIncomplete() || way.getNodesCount() < 1)
            return null;
        else {
            if ("backward".equals(role))
                return way.getNode(0);
            else
                return way.getNode(way.getNodesCount() - 1);
        }
    }

    private boolean gapNecessary(Way way, String role, Node lastNode) {
        if (way != null && !way.isIncomplete() && way.getNodesCount() >= 1) {
            Node firstNode = null;
            if ("backward".equals(role))
                firstNode = way.getNode(way.getNodesCount() - 1);
            else
                firstNode = way.getNode(0);
            if (lastNode != null && !lastNode.equals(firstNode))
                return true;
        }
        return false;
    }
}
