package net.onrc.onos.ofcontroller.topology;

/**
 * Class for storing information about a Topology Element: Switch, Port or
 * Link.
 */
public class TopologyElement {
    /**
     * The Element Type.
     */
    public enum Type {
	ELEMENT_UNKNOWN,	// Unknown element
	ELEMENT_SWITCH,		// Network Switch
	ELEMENT_PORT,		// Switch Port
	ELEMENT_LINK		// Unidirectional Link between Switch Ports
    }

    private Type elementType;		// The element type
    private long fromSwitchDpid = 0;	// The Switch DPID
    private int fromSwitchPort = 0;	// The Switch Port
    private long toSwitchDpid = 0;	// The Neighbor Switch DPID
    private int toSwitchPort = 0;	// The Neighbor Switch Port

    /**
     * Default constructor.
     */
    public TopologyElement() {
	elementType = Type.ELEMENT_UNKNOWN;
    }

    /**
     * Constructor to create a Topology Element for a Switch.
     *
     * @param switchDpid the Switch DPID.
     */
    public TopologyElement(long switchDpid) {
	this.elementType = Type.ELEMENT_SWITCH;
	this.fromSwitchDpid = switchDpid;
    }

    /**
     * Constructor to create a Topology Element for a Switch Port.
     *
     * @param switchDpid the Switch DPID.
     * @param switchPort the Switch Port.
     */
    public TopologyElement(long switchDpid, int switchPort) {
	this.elementType = Type.ELEMENT_PORT;
	this.fromSwitchDpid = switchDpid;
	this.fromSwitchPort = switchPort;
    }

    /**
     * Constructor to create a Topology Element for an unidirectional Link
     * between Switch Ports.
     *
     * @param fromSwitchDpid the Switch DPID the Link begins from.
     * @param fromSwitchPort the Switch Port the Link begins from.
     * @param toSwitchDpid the Switch DPID the Link ends to.
     * @param toSwitchPort the Switch Port the Link ends to.
     */
    public TopologyElement(long fromSwitchDpid, int fromSwitchPort,
			   long toSwitchDpid, int toSwitchPort) {
	this.elementType = Type.ELEMENT_LINK;
	this.fromSwitchDpid = fromSwitchDpid;
	this.fromSwitchPort = fromSwitchPort;
	this.toSwitchDpid = toSwitchDpid;
	this.toSwitchPort = toSwitchPort;
    }

    /**
     * Get the Element type.
     *
     * @return the Element type.
     */
    public TopologyElement.Type getType() {
	return elementType;
    }

    /**
     * Get the Switch DPID.
     *
     * NOTE: Applies for Type.ELEMENT_SWITCH and Type.ELEMENT_PORT
     *
     * @return the Switch DPID.
     */
    public long getSwitch() {
	return fromSwitchDpid;
    }

    /**
     * Get the Switch Port.
     *
     * NOTE: Applies for Type.ELEMENT_PORT
     *
     * @return the Switch Port.
     */
    public int getSwitchPort() {
	return fromSwitchPort;
    }

    /**
     * Get the Switch DPID the Link begins from.
     *
     * NOTE: Applies for Type.ELEMENT_LINK
     */
    public long getFromSwitch() {
	return fromSwitchDpid;
    }

    /**
     * Get the Switch Port the Link begins from.
     *
     * NOTE: Applies for Type.ELEMENT_LINK
     */
    public int getFromPort() {
	return fromSwitchPort;
    }

    /**
     * Get the Switch DPID the Link ends to.
     *
     * NOTE: Applies for Type.ELEMENT_LINK
     */
    public long getToSwitch() {
	return toSwitchDpid;
    }

    /**
     * Get the Switch Port the Link ends to.
     *
     * NOTE: Applies for Type.ELEMENT_LINK
     */
    public int getToPort() {
	return toSwitchPort;
    }

    /**
     * Get the Topology Element ID.
     *
     * The Topology Element ID has the following format:
     *   - Switch: "Switch=<HexLongDpid>"
     *     Example: "Switch=101"
     *   - Switch Port: "Port=<HexLongDpid>/<IntPortId>"
     *     Example: "Port=102/1"
     *   - Link: "Link=<FromHexLongDpid>/<FromIntPortId>/<ToHexLongDpid>/<ToIntPortId>"
     *     Example: "Link=101/2/103/4"
     *
     * NOTE: The Topology Element ID has no syntax meaning. It is used only to
     * uniquely identify a topology element.
     *
     * @return the Topology Element ID.
     */
    public String elementId() {
	switch (elementType) {
	case ELEMENT_SWITCH:
	    return "Switch=" + Long.toHexString(fromSwitchDpid);
	case ELEMENT_PORT:
	    return "Port=" +
		Long.toHexString(fromSwitchDpid) + "/" + fromSwitchPort;
	case ELEMENT_LINK:
	    return "Link=" +
		Long.toHexString(fromSwitchDpid) + "/" + fromSwitchPort + "/" +
		Long.toHexString(toSwitchDpid) + "/" + toSwitchPort;
	case ELEMENT_UNKNOWN:
	    return "Element=UNKNOWN";
	}

	assert(false);
	return null;
    }

    /**
     * Convert the Topology Element to a string.
     *
     * @return the Topology Element as a string.
     */
    @Override
    public String toString() {
	// For now, we just return the Element ID.
	return elementId();
    }
}
