package net.onrc.onos.core.util;

import java.util.ArrayList;

import org.codehaus.jackson.annotate.JsonProperty;

/**
 * The data forwarding path state from a source to a destination.
 */
public class DataPath {
    private SwitchPort srcPort;        // The source port
    private SwitchPort dstPort;        // The destination port
    private ArrayList<FlowEntry> flowEntries;    // The Flow Entries

    /**
     * Default constructor.
     */
    public DataPath() {
        srcPort = new SwitchPort();
        dstPort = new SwitchPort();
        flowEntries = new ArrayList<FlowEntry>();
    }

    /**
     * Get the data path source port.
     *
     * @return the data path source port.
     */
    @JsonProperty("srcPort")
    public SwitchPort srcPort() {
        return srcPort;
    }

    /**
     * Set the data path source port.
     *
     * @param srcPort the data path source port to set.
     */
    @JsonProperty("srcPort")
    public void setSrcPort(SwitchPort srcPort) {
        this.srcPort = srcPort;
    }

    /**
     * Get the data path destination port.
     *
     * @return the data path destination port.
     */
    @JsonProperty("dstPort")
    public SwitchPort dstPort() {
        return dstPort;
    }

    /**
     * Set the data path destination port.
     *
     * @param dstPort the data path destination port to set.
     */
    @JsonProperty("dstPort")
    public void setDstPort(SwitchPort dstPort) {
        this.dstPort = dstPort;
    }

    /**
     * Get the data path flow entries.
     *
     * @return the data path flow entries.
     */
    @JsonProperty("flowEntries")
    public ArrayList<FlowEntry> flowEntries() {
        return flowEntries;
    }

    /**
     * Set the data path flow entries.
     *
     * @param flowEntries the data path flow entries to set.
     */
    @JsonProperty("flowEntries")
    public void setFlowEntries(ArrayList<FlowEntry> flowEntries) {
        this.flowEntries = flowEntries;
    }

    /**
     * Apply Flow Path Flags to the pre-computed Data Path.
     *
     * @param flowPathFlags the Flow Path Flags to apply.
     */
    public void applyFlowPathFlags(FlowPathFlags flowPathFlags) {
        if (flowPathFlags == null) {
            return;        // Nothing to do
        }

        // Discard the first Flow Entry
        if (flowPathFlags.isDiscardFirstHopEntry()) {
            if (flowEntries.size() > 0) {
                flowEntries.remove(0);
            }
        }

        // Keep only the first Flow Entry
        if (flowPathFlags.isKeepOnlyFirstHopEntry()) {
            if (flowEntries.size() > 1) {
                FlowEntry flowEntry = flowEntries.get(0);
                flowEntries.clear();
                flowEntries.add(flowEntry);
            }
        }
    }

    /**
     * Remove Flow Entries that were deleted.
     */
    public void removeDeletedFlowEntries() {
        //
        // NOTE: We create a new ArrayList, and add only the Flow Entries
        // that are NOT FE_USER_DELETE.
        // This is sub-optimal: if it adds notable processing cost,
        // the Flow Entries container should be changed to LinkedList
        // or some other container that has O(1) cost of removing an entry.
        //

        // Test first whether any Flow Entry was deleted
        boolean foundDeletedFlowEntry = false;
        for (FlowEntry flowEntry : this.flowEntries) {
            if (flowEntry.flowEntryUserState() ==
                    FlowEntryUserState.FE_USER_DELETE) {
                foundDeletedFlowEntry = true;
                break;
            }
        }
        if (!foundDeletedFlowEntry) {
            return;            // Nothing to do
        }

        // Create a new collection and exclude the deleted flow entries
        ArrayList<FlowEntry> newFlowEntries = new ArrayList<FlowEntry>();
        for (FlowEntry flowEntry : this.flowEntries()) {
            if (flowEntry.flowEntryUserState() !=
                    FlowEntryUserState.FE_USER_DELETE) {
                newFlowEntries.add(flowEntry);
            }
        }
        setFlowEntries(newFlowEntries);
    }

    /**
     * Convert the data path to a string.
     * <p/>
     * The string has the following form:
     * [src=01:01:01:01:01:01:01:01/1111 flowEntry=<entry1> flowEntry=<entry2>
     * flowEntry=<entry3> dst=02:02:02:02:02:02:02:02/2222]
     *
     * @return the data path as a string.
     */
    @Override
    public String toString() {
        StringBuilder ret = new StringBuilder();

        ret.append("[src=" + this.srcPort.toString());

        for (FlowEntry fe : flowEntries) {
            ret.append(" flowEntry=" + fe.toString());
        }
        ret.append(" dst=" + this.dstPort.toString() + "]");

        return ret.toString();
    }
}
