package net.onrc.onos.graph;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IBaseObject;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IIpv4Address;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
import net.onrc.onos.ofcontroller.core.ISwitchStorage.SwitchState;
import net.onrc.onos.ofcontroller.util.FlowEntryId;
import net.onrc.onos.ofcontroller.util.FlowId;

import com.thinkaurelius.titan.core.TitanGraph;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.frames.FramedGraph;
import com.tinkerpop.frames.structures.FramedVertexIterable;
import com.tinkerpop.gremlin.java.GremlinPipeline;

public class GraphDBOperation implements IDBOperation {
	private GraphDBConnection conn;

	/**
	 * Create a GraphDBOperation instance from specified GraphDBConnection's instance.
	 * @param dbConnection an instance of GraphDBConnection
	 */
	public GraphDBOperation(GraphDBConnection dbConnection) {
		this.conn = dbConnection;
	}

	/**
	 * Create a GraphDBOperation instance from database configuration path.
	 * @param dbConfPath a path for database configuration file.
	 */
	public GraphDBOperation(final String dbConfPath) {
		this.conn = GraphDBConnection.getInstance(dbConfPath);
	}

	/**
	 * Create a new switch and return the created switch object.
	 * @param dpid DPID of the switch
	 */
	@Override
	public ISwitchObject newSwitch(String dpid) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		ISwitchObject obj = fg.addVertex(null,ISwitchObject.class);
		if (obj != null) {
			obj.setType("switch");
			obj.setDPID(dpid);
		}
		return obj;
	}

	/**
	 * Search and get a switch object with DPID.
	 * @param dpid DPID of the switch
	 */
	@Override
	public ISwitchObject searchSwitch(String dpid) {

		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		if ( fg == null ) return null;
		Iterator<ISwitchObject> it = fg.getVertices("dpid",dpid,ISwitchObject.class).iterator();
		return (it.hasNext()) ? it.next() : null;

	}

	/**
	 * Search and get an active switch object with DPID.
	 * @param dpid DPID of the switch
	 */
	@Override
	public ISwitchObject searchActiveSwitch(String dpid) {

	    ISwitchObject sw = searchSwitch(dpid);
	    if ((sw != null) &&
	        sw.getState().equals(SwitchState.ACTIVE.toString())) {
	        return sw;
	    }
	    return null;
	}

	/**
	 * Get all switch objects.
	 */
	@Override
	public Iterable<ISwitchObject> getAllSwitches() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		Iterable<ISwitchObject> switches =  fg.getVertices("type","switch",ISwitchObject.class);
		return switches;
	}

	/**
	 * Get all active switch objects.
	 */
	@Override
	public Iterable<ISwitchObject> getActiveSwitches() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		Iterable<ISwitchObject> switches =  fg.getVertices("type","switch",ISwitchObject.class);
		List<ISwitchObject> activeSwitches = new ArrayList<ISwitchObject>();

		for (ISwitchObject sw: switches) {
			if(sw.getState().equals(SwitchState.ACTIVE.toString())) {
				activeSwitches.add(sw);
			}
		}
		return activeSwitches;
	}

	/**
	 * Get all inactive switch objects.
	 */
	@Override
	public Iterable<ISwitchObject> getInactiveSwitches() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		Iterable<ISwitchObject> switches =  fg.getVertices("type","switch",ISwitchObject.class);
		List<ISwitchObject> inactiveSwitches = new ArrayList<ISwitchObject>();

		for (ISwitchObject sw: switches) {
			if(sw.getState().equals(SwitchState.INACTIVE.toString())) {
				inactiveSwitches.add(sw);
			}
		}
		return inactiveSwitches;
	}

	/**
	 * Get all flow entries' objects where their switches are not updated.
	 */
	@Override
	public Iterable<IFlowEntry> getAllSwitchNotUpdatedFlowEntries() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		//TODO: Should use an enum for flow_switch_state
		return fg.getVertices("switch_state", "FE_SWITCH_NOT_UPDATED", IFlowEntry.class);
	}

	/**
	 * Remove specified switch.
	 * @param sw switch object to remove
	 */
	@Override
	public void removeSwitch(ISwitchObject sw) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		fg.removeVertex(sw.asVertex());
	}

	@Override
	public IPortObject newPort(String dpid, Short portNumber) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		IPortObject obj = fg.addVertex(null,IPortObject.class);
		if (obj != null) {
			obj.setType("port");
			String id = dpid + portNumber.toString();
			obj.setPortId(id);
			obj.setNumber(portNumber);
		}
		return obj;

	}

	/**
	 * Create a port having specified port number.
	 * @param portNumber port number
	 */
	@Override
	@Deprecated
	public IPortObject newPort(Short portNumber) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		IPortObject obj = fg.addVertex(null,IPortObject.class);
		if (obj != null) {
			obj.setType("port");
			obj.setNumber(portNumber);
		}
		return obj;
	}

	/**
	 * Search and get a port object of specified switch and port number.
	 * @param dpid DPID of a switch
	 * @param number port number of the switch's port
	 */
	@Override
	public IPortObject searchPort(String dpid, Short number) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		if ( fg == null ) return null;
		String id = dpid + number.toString();
		Iterator<IPortObject> ports =  fg.getVertices("port_id",id,IPortObject.class).iterator();
		if ( ports.hasNext() ) {
			return ports.next();
		} else {
			return null;
		}
	}

	/**
	 * Remove the specified switch port.
	 * @param port switch port object to remove
	 */
	@Override
	public void removePort(IPortObject port) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
//		EventGraph<TitanGraph> eg = conn.getEventGraph();
		if (fg != null) fg.removeVertex(port.asVertex());
	}

	/**
	 * Create and return a device object.
	 */
	@Override
	public IDeviceObject newDevice() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		IDeviceObject obj = fg.addVertex(null,IDeviceObject.class);
		if (obj != null) obj.setType("device");
		return obj;
	}

	/**
	 * Search and get a device object having specified MAC address.
	 * @param macAddr MAC address to search and get
	 */
	@Override
	public IDeviceObject searchDevice(String macAddr) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		if ( fg == null ) return null;
		Iterator<IDeviceObject> devices =  fg.getVertices("dl_addr",macAddr, IDeviceObject.class).iterator();
		if ( devices.hasNext() ) {
			return devices.next();
		} else {
			return null;
		}
	}

	/**
	 * Get all devices.
	 */
	@Override
	public Iterable<IDeviceObject> getDevices() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		return fg != null ? fg.getVertices("type","device",IDeviceObject.class) : null;
	}

	/**
	 * Remove the specified device.
	 * @param dev a device object to remove
	 */
	@Override
	public void removeDevice(IDeviceObject dev) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		if (fg != null) fg.removeVertex(dev.asVertex());
	}

	public IIpv4Address newIpv4Address() {
		return newVertex("ipv4Address", IIpv4Address.class);
	}

	private <T extends IBaseObject> T newVertex(String type, Class<T> vertexType) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		T newVertex = fg.addVertex(null, vertexType);
		if (newVertex != null) {
			newVertex.setType(type);
		}
		return newVertex;
	}

	public IIpv4Address searchIpv4Address(int intIpv4Address) {
		return searchForVertex("ipv4_address", intIpv4Address, IIpv4Address.class);
	}

	private <T> T searchForVertex(String propertyName, Object propertyValue, Class<T> vertexType) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		if (fg != null) {
			Iterator<T> it =
					fg.getVertices(propertyName, propertyValue, vertexType).iterator();
			if (it.hasNext()) {
				return it.next();
			}
		}
		return null;
	}

	public IIpv4Address ensureIpv4Address(int intIpv4Address) {
		IIpv4Address ipv4Vertex = searchIpv4Address(intIpv4Address);
		if (ipv4Vertex == null) {
			ipv4Vertex = newIpv4Address();
			ipv4Vertex.setIpv4Address(intIpv4Address);
		}
		return ipv4Vertex;
	}

	public void removeIpv4Address(IIpv4Address ipv4Address) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		fg.removeVertex(ipv4Address.asVertex());
	}

	/**
	 * Create and return a flow path object.
	 */
	@Override
	public IFlowPath newFlowPath() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		IFlowPath flowPath = fg.addVertex(null, IFlowPath.class);
		if (flowPath != null) flowPath.setType("flow");
		return flowPath;
	}

	/**
	 * Search and get a flow path object with specified flow ID.
	 * @param flowId flow ID to search
	 */
	@Override
	public IFlowPath searchFlowPath(FlowId flowId) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		if ( fg == null ) return null;
		Iterator<IFlowPath> flowpaths = fg.getVertices("flow_id", flowId.toString(), IFlowPath.class).iterator();
		if ( flowpaths.hasNext() ) {
			return flowpaths.next();
		} else {
			return null;
		}
	}

	/**
	 * Get a flow path object with a flow entry.
	 * @param flowEntry flow entry object
	 */
	@Override
	public IFlowPath getFlowPathByFlowEntry(IFlowEntry flowEntry) {
		GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
		pipe.start(flowEntry.asVertex()).out("flow");
		FramedVertexIterable<IFlowPath> r = new FramedVertexIterable<IFlowPath>(conn.getFramedGraph(),
				pipe, IFlowPath.class);
		return r.iterator().hasNext() ? r.iterator().next() : null;
	}

	/**
	 * Get all flow path objects.
	 */
	@Override
	public Iterable<IFlowPath> getAllFlowPaths() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		Iterable<IFlowPath> flowPaths = fg.getVertices("type", "flow", IFlowPath.class);

		List<IFlowPath> nonNullFlows = new ArrayList<IFlowPath>();

		for (IFlowPath fp: flowPaths) {
			if (fp.getFlowId() != null) {
				nonNullFlows.add(fp);
			}
		}
		return nonNullFlows;
	}

    /**
     * Remove the specified flow path.
     * @param flowPath flow path object to remove
     */
	@Override
	public void removeFlowPath(IFlowPath flowPath) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		fg.removeVertex(flowPath.asVertex());
	}

	/**
	 * Create and return a flow entry object.
	 */
	@Override
	public IFlowEntry newFlowEntry() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		IFlowEntry flowEntry = fg.addVertex(null, IFlowEntry.class);
		if (flowEntry != null) flowEntry.setType("flow_entry");
		return flowEntry;
	}

	/**
	 * Search and get a flow entry object with flow entry ID.
	 * @param flowEntryId flow entry ID to search
	 */
	@Override
	public IFlowEntry searchFlowEntry(FlowEntryId flowEntryId) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		if ( fg == null ) return null;
		Iterator<IFlowEntry> flowentries = fg.getVertices("flow_entry_id", flowEntryId.toString(), IFlowEntry.class).iterator();
		if ( flowentries.hasNext() ) {
			return flowentries.next();
		} else {
			return null;
		}
	}

	/**
	 * Get all flow entry objects.
	 */
	@Override
	public Iterable<IFlowEntry> getAllFlowEntries() {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();

		return fg.getVertices("type", "flow_entry", IFlowEntry.class);
	}

	/**
	 * Remove the specified flow entry.
	 * @param flowEntry flow entry object to remove
	 */
	@Override
	public void removeFlowEntry(IFlowEntry flowEntry) {
		FramedGraph<TitanGraph> fg = conn.getFramedGraph();
		fg.removeVertex(flowEntry.asVertex());
	}

	/**
	 * Get the instance of GraphDBConnection assigned to this class.
	 */
	@Override
	public IDBConnection getDBConnection() {
		return conn;
	}

	/**
	 * Commit changes for the graph.
	 */
	@Override
	public void commit() {
		conn.commit();
	}

	/**
	 * Rollback changes for the graph.
	 */
	@Override
	public void rollback() {
		conn.rollback();
	}

	/**
	 * Close the connection of the assigned GraphDBConnection.
	 */
	@Override
	public void close() {
		conn.close();
	}


}
