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

import java.util.ArrayList;

import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.Channel;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.ChannelDiGraph;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.LeadsTo;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.OSMGraph;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.OSMRelation;

/**
 * TurnRestrictionChecke prüft einen OSMGraphen auf vorhandene
 * Abbiegerestriktionen in den Relationen und paßt die Abiegerestriktionen der
 * Channels des aus dem OSMGraphen erzeugten ChannelDigraphen dementsprechend
 * an. wird vom ChannelDigraphBuilder aufgerufen
 *
 * @author Jörg Possin
 */
public class TurnRestrictionChecker {

    private final ArrayList<OSMRelation> turnrestrictionsrelations = new ArrayList<>();
    private final ChannelDiGraph channelDigraph;
    private int relationpointer;
    private LeadsTo tempLeadsTo;

    public TurnRestrictionChecker(OSMGraph graph, ChannelDiGraph channelDigraph) {
        // von den Relationen des Graphen nur die Abbiegevorschriften kopieren
        for (int i = 0; i < graph.getRelations().length; i++) {
            if (graph.getRelations()[i].hasKey("type")) {
                if (graph.getRelations()[i].getValue("type").equals(
                "restriction")) {
                    turnrestrictionsrelations.add(graph.getRelations()[i]);
                }
            }
        }
        this.channelDigraph = channelDigraph;
    }

    private boolean checkForRelations(Channel channel) {
        for (int k = 0; k < turnrestrictionsrelations.size(); k++) {
            //log.trace("betrachte relation in liste an position:" + k);
            for (int i = 0; i < channel.getWays().size(); i++) {
                if (turnrestrictionsrelations.get(k).getMember("from").getId() == channel
                        .getWays().get(i).getId()
                        && turnrestrictionsrelations.get(k).getMember("via")
                        .getId() == channel.getToNode().getId()) {
                    relationpointer = k;
                    return true;
                }
            }
        }
        return false;
    }

    private void produceLeadsToFromRelation(Channel fromChannel,
            Channel toChannel) {
        if (toChannel.getWays().contains(
                turnrestrictionsrelations.get(relationpointer).getMember("to"))) {
            if (turnrestrictionsrelations.get(relationpointer).getValue(
            "restriction").startsWith("only")) {

                tempLeadsTo = new LeadsTo(fromChannel, toChannel);
                channelDigraph.addLeadsTo(tempLeadsTo);
                toChannel.addPredChannel(fromChannel);
            /*
             * der no_* Fall: wie oben, nur das hier nichts geschieht
             */
            } else if (turnrestrictionsrelations.get(relationpointer).getValue(
            "restriction").startsWith("no")) {
                for (int i = 0; i < fromChannel.getToNode()
                .getOutgoingChannels().size(); i++) {
                    if (fromChannel.getToNode().getOutgoingChannels().get(i) != toChannel) {
                        tempLeadsTo = new LeadsTo(fromChannel, fromChannel
                                .getToNode().getOutgoingChannels().get(i));
                        channelDigraph.addLeadsTo(tempLeadsTo);
                        fromChannel.getToNode().getOutgoingChannels().get(i)
                        .addPredChannel(fromChannel);
                    }
                }
            }
        }

    }

    /**
     * startet die LeadsTo Erstellung
     */
    public void createLeadsTo() {
        Channel tempChannel;
        for (int i = 0; i < channelDigraph.getChannels().size(); i++) {
            tempChannel = channelDigraph.getChannelAtPosition(i);
            boolean isInRelation = checkForRelations(tempChannel);
            for (int j = 0; j < tempChannel.getToNode().getOutgoingChannels()
            .size(); j++) {
                if (isInRelation) {
                    produceLeadsToFromRelation(tempChannel, tempChannel
                            .getToNode().getOutgoingChannels().get(j));
                    // es wird nur dann ein leadsTo erzeugt, wenn der vom
                    // Endknoten des Channels
                    // ausgehende Channel NICHT der Channel in Rückrichtung ist
                    // Ausnahme: es gibt nur diesen einen Channel (Wegende eines
                    // Ways, der an keine weitere
                    // Straße trifft
                } else if (tempChannel.getBackChannelID() != tempChannel
                        .getToNode().getOutgoingChannels().get(j).getNewid()
                        || tempChannel.getToNode().getOutgoingChannels().size() == 1) {
                    tempLeadsTo = new LeadsTo(tempChannel, tempChannel
                            .getToNode().getOutgoingChannels().get(j));
                    channelDigraph.addLeadsTo(tempLeadsTo);
                    tempChannel.getToNode().getOutgoingChannels().get(j)
                    .addPredChannel(tempChannel);
                }
            }
        }
    }
}
