package net.onrc.onos.core.newintent;

import com.google.common.base.Predicates;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import net.onrc.onos.api.flowmanager.FlowId;
import net.onrc.onos.api.flowmanager.FlowIdGenerator;
import net.onrc.onos.api.flowmanager.FlowLink;
import net.onrc.onos.api.flowmanager.PacketPathFlow;
import net.onrc.onos.api.flowmanager.Path;
import net.onrc.onos.api.newintent.Intent;
import net.onrc.onos.api.newintent.IntentIdGenerator;
import net.onrc.onos.api.newintent.PointToPointIntent;
import net.onrc.onos.core.intent.ConstrainedBFSTree;
import net.onrc.onos.core.matchaction.action.Action;
import net.onrc.onos.core.matchaction.match.Match;
import net.onrc.onos.core.matchaction.match.PacketMatch;
import net.onrc.onos.core.topology.BaseTopology;
import net.onrc.onos.core.topology.ITopologyService;
import net.onrc.onos.core.topology.LinkEvent;
import net.onrc.onos.core.topology.Switch;
import net.onrc.onos.core.util.SwitchPort;

import java.util.Arrays;
import java.util.List;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * A intent compiler for {@link PointToPointIntent}.
 */
public class PointToPointIntentCompiler
        extends AbstractFlowGeneratingIntentCompiler<PointToPointIntent> {

    private final ITopologyService topologyService;

    /**
     * Constructs an intent compiler for {@link PointToPointIntent} with the specified
     * ID generator and topology service.
     *
     * @param intentIdGenerator intent ID generator
     * @param topologyService topology service
     */
    public PointToPointIntentCompiler(IntentIdGenerator intentIdGenerator,
                                      FlowIdGenerator flowIdGenerator,
                                      ITopologyService topologyService) {
        super(intentIdGenerator, flowIdGenerator);
        this.topologyService = checkNotNull(topologyService);
    }

    @Override
    public List<Intent> compile(PointToPointIntent intent) {
        Match match = intent.getMatch();
        if (!(match instanceof PacketMatch)) {
            throw new IntentCompilationException(
                    "intent has unsupported type of match object: " + match
            );
        }

        SwitchPort ingress = intent.getIngressPort();
        SwitchPort egress = intent.getEgressPort();
        FlowId flowId = getNextFlowId();
        Path path = calculatePath(ingress, egress);

        List<Action> actions = packActions(intent, intent.getEgressPort());

        PacketPathFlow flow = new PacketPathFlow(flowId, (PacketMatch) match,
                ingress.getPortNumber(), path, actions, 0, 0);
        return Arrays.asList((Intent) new PathFlowIntent(getNextId(), flow));
    }

    /**
     * Calculates a path between the specified ingress port and the specified egress port.
     * @param ingress ingress port
     * @param egress egress port
     * @return path
     */
    private Path calculatePath(SwitchPort ingress, SwitchPort egress) {
        BaseTopology topology = topologyService.getTopology();
        Switch source = topology.getSwitch(ingress.getDpid());
        Switch destination = topology.getSwitch(egress.getDpid());

        if (source == null) {
            throw new PathNotFoundException("source switch not found: " + ingress.getDpid());
        }
        if (destination == null) {
            throw new PathNotFoundException("destination switch not found: " + egress.getDpid());
        }

        ConstrainedBFSTree tree = new ConstrainedBFSTree(source);
        net.onrc.onos.core.intent.Path path = tree.getPath(destination);
        return convertPath(path);
    }

    /**
     * Converts a {@link net.onrc.onos.core.intent.Path} to {@link Path}.
     *
     * @param path original {@link net.onrc.onos.core.intent.Path}
     * @return converted {@link Path}
     */
    static Path convertPath(net.onrc.onos.core.intent.Path path) {
        // would like to use filter and transform, but Findbugs detects
        // inconsistency of use of @Nullable annotation. Then, use of the
        // transform is avoided.
        // Ref: https://code.google.com/p/guava-libraries/issues/detail?id=1812
        // TODO: replace with transform when the above issue is resolved
        ImmutableList<LinkEvent> events = FluentIterable.from(path)
                .filter(Predicates.notNull())
                .toList();

        Path converted = new Path();
        for (LinkEvent event: events) {
            converted.add(new FlowLink(event.getSrc(), event.getDst()));
        }
        return converted;
    }
}
