package net.onrc.onos.api.flowmanager;

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

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

import net.onrc.onos.api.flowmanager.FlowBatchOperation.Operator;
import net.onrc.onos.core.matchaction.MatchAction;
import net.onrc.onos.core.matchaction.MatchActionId;
import net.onrc.onos.core.matchaction.MatchActionOperationEntry;
import net.onrc.onos.core.matchaction.MatchActionOperations;
import net.onrc.onos.core.matchaction.MatchActionOperationsId;
import net.onrc.onos.core.matchaction.action.Action;
import net.onrc.onos.core.matchaction.action.OutputAction;
import net.onrc.onos.core.matchaction.match.PacketMatch;
import net.onrc.onos.core.util.Dpid;
import net.onrc.onos.core.util.IdGenerator;
import net.onrc.onos.core.util.PortNumber;
import net.onrc.onos.core.util.SwitchPort;

/**
 * A {@link Flow} object expressing the multipoints-to-point tree flow for the
 * packet layer.
 * <p>
 * NOTE: This class might generate the {@link MatchAction} operations which
 * includes the MAC address modifications or other the label-switching-like
 * schemes.
 */
public class SingleDstTreeFlow extends Flow {
    private final PacketMatch match;
    private final Set<SwitchPort> ingressPorts;
    private final Tree tree;
    private final List<Action> egressActions;

    /**
     * Default constructor for Kryo deserialization.
     */
    @Deprecated
    protected SingleDstTreeFlow() {
        match = null;
        ingressPorts = null;
        tree = null;
        egressActions = null;
    }

    /**
     * Creates new instance using Tree object.
     *
     * @param id ID for this object
     * @param match the traffic filter for the tree
     * @param ingressPorts the set of ingress ports of the tree
     * @param tree the Tree object specifying tree topology for this object
     * @param egressActions the list of {@link Action} objects to be executed at
     *        the egress edge switch
     */
    public SingleDstTreeFlow(FlowId id, PacketMatch match,
            Collection<SwitchPort> ingressPorts, Tree tree, List<Action> egressActions) {
        super(id);
        this.match = checkNotNull(match);
        this.ingressPorts = new HashSet<>(checkNotNull(ingressPorts));
        this.tree = checkNotNull(tree);
        this.egressActions = new LinkedList<>(checkNotNull(egressActions));

        // TODO: check if the tree is a MP2P tree.
        // TODO: check consistency between ingressPorts and tree topology.
    }

    /**
     * Gets the ingress ports of the tree.
     *
     * @return the ingress ports of the tree
     */
    public Collection<SwitchPort> getIngressPorts() {
        return ImmutableSet.copyOf(ingressPorts);
    }

    /**
     * Gets the tree.
     *
     * @return the tree object
     */
    public Tree getTree() {
        return tree;
    }

    /**
     * Gets the list of actions at the egress edge switch.
     *
     * @return the list of actions at the egress edge switch
     */
    public List<Action> getEgressActions() {
        return ImmutableList.copyOf(egressActions);
    }

    @Override
    public PacketMatch getMatch() {
        return match;
    }

    @Override
    public List<MatchActionOperations> compile(Operator op,
            IdGenerator<MatchActionId> maIdGenerator,
            IdGenerator<MatchActionOperationsId> maoIdGenerator) {
        switch (op) {
        case ADD:
            return compileAddOperation(maIdGenerator, maoIdGenerator);
        case REMOVE:
            return compileRemoveOperation();
        default:
            throw new UnsupportedOperationException("Unknown operation.");
        }
    }

    private MatchAction createMatchAction(SwitchPort port, List<Action> actions,
            IdGenerator<MatchActionId> maIdGenerator) {
        checkNotNull(port);
        checkNotNull(actions);

        return new MatchAction(maIdGenerator.getNewId(), port, getMatch(), actions);
    }

    /**
     * Generates MatchAactionOperations at inner ports and at the egress switch.
     *
     * @param egressSwitch the egress switch of the tree
     * @param inPorts a map of a set of incoming ports on each switch in the
     *        tree
     * @param outPorts a map of outgoing port on each switch in the tree
     * @param maIdGenerator ID generator for MatchAction objects
     * @param maoIdGenerator ID generator for MatchActionOperations objects
     * @return the operations at inner ports and egress switch
     */
    private MatchActionOperations generateFirstAddOperations(
            Dpid egressSwitch,
            Map<Dpid, Set<PortNumber>> inPorts,
            Map<Dpid, PortNumber> outPorts,
            IdGenerator<MatchActionId> maIdGenerator,
            IdGenerator<MatchActionOperationsId> maoIdGenerator) {
        MatchActionOperations firstOps =
                new MatchActionOperations(maoIdGenerator.getNewId());
        for (Entry<Dpid, Set<PortNumber>> innerSw : inPorts.entrySet()) {
            for (PortNumber innerPortNumber : innerSw.getValue()) {
                SwitchPort innerPort = new SwitchPort(innerSw.getKey(), innerPortNumber);
                MatchAction ma;
                if (innerPort.getDpid().equals(egressSwitch)) {
                    ma = createMatchAction(innerPort, getEgressActions(), maIdGenerator);
                } else {
                    PortNumber outputPortNumber = checkNotNull(
                            outPorts.get(innerPort.getDpid()),
                            String.format("The tree has no output port at %s",
                                    innerPort.getDpid()));
                    ma = createMatchAction(innerPort,
                            Arrays.asList((Action) new OutputAction(outputPortNumber)),
                            maIdGenerator);
                }
                firstOps.addOperation(new MatchActionOperationEntry(
                        MatchActionOperations.Operator.ADD, ma));
            }
        }
        return firstOps;
    }

    /**
     * Generates MatchActionOperations for ingress switches in the tree.
     *
     * @param egressSwitch the egress switch of the tree
     * @param outPorts a map of outgoing port on each switch in the tree
     * @param maIdGenerator ID generator for MatchAction objects
     * @param maoIdGenerator ID generator for MatchActionOperations objects
     * @return operations at ingress switches in the tree
     */
    private MatchActionOperations generateSecondAddOperations(
            Dpid egressSwitch,
            Map<Dpid, PortNumber> outPorts,
            IdGenerator<MatchActionId> maIdGenerator,
            IdGenerator<MatchActionOperationsId> maoIdGenerator) {
        MatchActionOperations secondOps =
                new MatchActionOperations(maoIdGenerator.getNewId());
        for (SwitchPort port : getIngressPorts()) {
            PortNumber outputPort = outPorts.get(port.getDpid());
            if (outputPort == null) {
                if (port.getDpid().equals(egressSwitch)) {
                    MatchAction ma = createMatchAction(
                            port, getEgressActions(), maIdGenerator);
                    secondOps.addOperation(new MatchActionOperationEntry(
                            MatchActionOperations.Operator.ADD, ma));
                } else {
                    throw new IllegalStateException(String.format(
                            "The switch %s specified as one of ingress ports "
                                    + "does not have path to the egress switch.",
                            port.getDpid()));
                }
            } else {
                MatchAction ma = createMatchAction(port,
                        Arrays.asList((Action) new OutputAction(outputPort)),
                        maIdGenerator);
                secondOps.addOperation(new MatchActionOperationEntry(
                        MatchActionOperations.Operator.ADD, ma));
            }
        }
        return secondOps;
    }

    private List<MatchActionOperations> compileAddOperation(
            IdGenerator<MatchActionId> maIdGenerator,
            IdGenerator<MatchActionOperationsId> maoIdGenerator) {
        checkNotNull(tree);
        checkState(tree.size() > 0, "Tree object has no link.");

        // TODO: check consistency of the tree topology

        // collect input ports and output ports checking consistency
        Map<Dpid, PortNumber> outPorts = new HashMap<>();
        Map<Dpid, Set<PortNumber>> inPorts = new HashMap<>();
        for (FlowLink link : tree) {
            SwitchPort srcPort = link.getSrcSwitchPort();
            if (outPorts.containsKey(srcPort.getDpid())) {
                throw new IllegalStateException(
                        String.format("Dpid:%s has multiple output ports.",
                                srcPort.getDpid()));
            }
            outPorts.put(srcPort.getDpid(), srcPort.getPortNumber());

            SwitchPort dstPort = link.getDstSwitchPort();
            Set<PortNumber> inPortNumbers = inPorts.get(dstPort.getDpid());
            if (inPortNumbers == null) {
                inPortNumbers = new HashSet<>();
            }
            inPortNumbers.add(dstPort.getPortNumber());
            inPorts.put(dstPort.getDpid(), inPortNumbers);
        }

        // find the egress switch
        Set<Dpid> egressSwitches = new HashSet<>(inPorts.keySet());
        egressSwitches.removeAll(outPorts.keySet());
        checkState(egressSwitches.size() == 1,
                "The specified tree is not a single destination tree.");
        Dpid egressSwitch = egressSwitches.iterator().next();

        MatchActionOperations firstOps = generateFirstAddOperations(
                egressSwitch, inPorts, outPorts, maIdGenerator, maoIdGenerator);
        checkState(firstOps.size() > 0,
                "No operations found for the first set of operations.");

        MatchActionOperations secondOps = generateSecondAddOperations(
                egressSwitch, outPorts, maIdGenerator, maoIdGenerator);
        checkState(secondOps.size() > 0,
                "No operations found for the second set of operations.");

        return Arrays.asList(firstOps, secondOps);
    }

    private List<MatchActionOperations> compileRemoveOperation() {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException(
                "REMOVE operation is not implemented yet.");
    }
}
