Added functionality to delete links and to add links to remote switches that have a link to a local switch.
diff --git a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
index d63624c..df609e7 100644
--- a/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
+++ b/src/main/java/net/floodlightcontroller/core/IOFSwitch.java
@@ -338,6 +338,12 @@
     Object removeAttribute(String name);
 
     /**
+     * Setup an unconnected switch with the info required.
+     * @param dpid of the switch
+     */
+    public void setupRemoteSwitch(Long dpid);
+    
+    /**
      * Clear all flowmods on this switch
      */
     public void clearAllFlowMods();
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
index dff00fd..bf5aaf7 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFSwitchImpl.java
@@ -268,7 +268,7 @@
     public void disconnectOutputStream() {
         channel.close();
     }
-
+    
     @Override
     @JsonIgnore
     public void setFeaturesReply(OFFeaturesReply featuresReply) {
@@ -854,4 +854,11 @@
     public byte getTables() {
         return tables;
     }
+
+
+	@Override
+	public void setupRemoteSwitch(Long dpid) {
+	    this.datapathId = dpid;
+	    this.stringId = HexString.toHexString(this.datapathId);
+	}
 }
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkStorage.java b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkStorage.java
index 6d66a49..a764227 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkStorage.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/ILinkStorage.java
@@ -11,26 +11,37 @@
      * Link creation
      */
 	public void update(Link link, DM_OPERATION op);
+	public void update(Link link, LinkInfo linkinfo, DM_OPERATION op);
 	public void update(List<Link> List, DM_OPERATION op);
-	
+
 	/*
 	 *  Add Linkinfo
 	 */
-	public void update(Link link, LinkInfo linkinfo, DM_OPERATION op);
+	public void addOrUpdateLink (Link link, LinkInfo linkinfo, DM_OPERATION op);
 	
 	/*
-	 * Get Links from Storage
-	 *  If dpid and port both are specified specific link is retrieved
-	 *  If only dpid is set all links associated with Switch are retrieved
+	 * Delete a single link
 	 */
-	public List<Link> getLinks(Long dpid, int port);
+	public void deleteLink(Link link);
 
 	/*
 	 * Delete links associated with dpid and port 
 	 * If only dpid is used, All links associated for switch are removed
 	 * Useful for port up/down and also switch join/remove events
 	 */ 
-	public void deleteLinks(Long dpid, int port);
+	public void deleteLinksOnPort(Long dpid, short port);
+	
+	/*
+	 * Delete a list of links
+	 */
+	public void deleteLinks(List<Link> links);
+
+	/*
+	 * Get Links from Storage
+	 *  If dpid and port both are specified specific link is retrieved
+	 *  If only dpid is set all links associated with Switch are retrieved
+	 */
+	public List<Link> getLinks(Long dpid, short port);
 	
 	/*
 	 * Init with Storage conf
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
index 8ad31c2..0247544 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkDiscoveryManager.java
@@ -47,10 +47,12 @@
 import net.floodlightcontroller.core.IInfoProvider;
 import net.floodlightcontroller.core.IOFMessageListener;
 import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.internal.OFSwitchImpl;
 import net.floodlightcontroller.core.IOFSwitchListener;
 import net.floodlightcontroller.core.annotations.LogMessageCategory;
 import net.floodlightcontroller.core.annotations.LogMessageDoc;
 import net.floodlightcontroller.core.annotations.LogMessageDocs;
+//import net.floodlightcontroller.core.internal.SwitchStorageImpl;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
@@ -192,6 +194,7 @@
 
     // Storage
     protected LinkStorageImpl linkStore;
+   // protected SwitchStorageImpl swStore;
     
     /**
      * Flag to indicate if automatic port fast is enabled or not.
@@ -200,6 +203,12 @@
     boolean autoPortFastFeature = false;
 
     /**
+     * Map of remote switches that are not connected to this controller. This
+     * is used to learn remote switches in a distributed controller.
+     */
+    protected Map<Long, IOFSwitch> remoteSwitches;
+    
+    /**
      * Map from link to the most recent time it was verified functioning
      */
     protected Map<Link, LinkInfo> links;
@@ -509,6 +518,34 @@
     }
 
     /**
+     * Learn remote switches when running as a distributed controller
+     */
+    protected IOFSwitch addRemoteSwitch(long sw, short port) {
+    	IOFSwitch remotesw = null;
+    	
+    	// add a switch if we have not seen it before
+        if (!remoteSwitches.containsKey(sw)) {
+        	remotesw = new OFSwitchImpl();
+        	remotesw.setupRemoteSwitch(sw);
+        	remoteSwitches.put(remotesw.getId(), remotesw);
+        	log.debug("addRemoteSwitch(): added fake remote sw {}", remotesw);
+        }
+        
+        // add the port if we have not seen it before
+        if (remotesw.getPort(port) != null) {
+        	OFPhysicalPort remoteport = new OFPhysicalPort();
+        	remoteport.setPortNumber(port);
+        	remoteport.setName("fake_" + port);
+        	remoteport.setConfig(0); 
+        	remoteport.setState(0);
+        	remotesw.setPort(remoteport);
+        	log.debug("addRemoteSwitch(): added fake remote port {} to sw {}", remoteport, remotesw);
+        }
+        
+        return remotesw;
+    }
+    
+    /**
      * Send link discovery message out of a given switch port.
      * The discovery message may be a standard LLDP or a modified
      * LLDP, where the dst mac address is set to :ff.  
@@ -769,6 +806,11 @@
                     lldptlv.getValue()[2] == (byte)0xe1 && lldptlv.getValue()[3] == 0x0) {
                 ByteBuffer dpidBB = ByteBuffer.wrap(lldptlv.getValue());
                 remoteSwitch = floodlightProvider.getSwitches().get(dpidBB.getLong(4));
+                if (remoteSwitch == null) {
+                	// floodlight LLDP coming from a remote switch connected to a different controller
+                	// add it to our cache of unconnected remote switches
+                	remoteSwitch = addRemoteSwitch(dpidBB.getLong(4), remotePort);
+                }
             } else if (lldptlv.getType() == 12 && lldptlv.getLength() == 8){
                 otherId = ByteBuffer.wrap(lldptlv.getValue()).getLong();
                 if (myId == otherId)
@@ -1161,7 +1203,7 @@
                 // remove link from storage.
                 removeLinkFromStorage(lt);
 
-                // Write link to network map
+                // remote link from network map
                 linkStore.update(lt, DM_OPERATION.DELETE);
                 
                 // TODO  Whenever link is removed, it has to checked if
@@ -1211,6 +1253,7 @@
                     ((byte)OFPortReason.OFPPR_MODIFY.ordinal() ==
                     ps.getReason() && !portEnabled(ps.getDesc()))) {
                 deleteLinksOnPort(npt, "Port Status Changed");
+                //swStore.deletePort(HexString.toHexString(npt.getNodeId()), npt.getPortId());
                 LDUpdate update = new LDUpdate(sw, port, UpdateOperation.PORT_DOWN);
                 updates.add(update);
                 linkDeleted = true;
@@ -1871,6 +1914,11 @@
         this.linkStore = new LinkStorageImpl();
         this.linkStore.init("/tmp/cassandra.titan");
         
+        // Initialieze the switch storage connector to the network map. We may need to delete switches.
+        // TODO find a better place to delete switches and ports from network map
+        // this.swStore = new SwitchStorageImpl();
+        // this.swStore.init("/tmp/cassandra.titan");
+        
         ScheduledExecutorService ses = threadPool.getScheduledExecutor();
 
         // To be started by the first switch connection
diff --git a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
index 16770bd..9c0ee4e 100644
--- a/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
+++ b/src/main/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImpl.java
@@ -18,126 +18,169 @@
 import com.tinkerpop.blueprints.Direction;
 import com.tinkerpop.blueprints.TransactionalGraph.Conclusion;
 import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.blueprints.Edge;
 import com.tinkerpop.gremlin.java.GremlinPipeline;
 
 public class LinkStorageImpl implements ILinkStorage {
 	public TitanGraph graph;
 	protected static Logger log = LoggerFactory.getLogger(LinkStorageImpl.class);
-	
+
 	@Override
 	public void update(Link link, DM_OPERATION op) {
-		update (link, (LinkInfo)null, op);
+		update(link, (LinkInfo)null, op);
 	}
 
 	@Override
 	public void update(List<Link> links, DM_OPERATION op) {
-		log.debug("LinkStorage:update(): {} {}", op, links);
-
 		for (Link lt: links) {
-			update(lt, op);
+			update(lt, (LinkInfo)null, op);
 		}
 	}
 
 	@Override
 	public void update(Link link, LinkInfo linkinfo, DM_OPERATION op) {
-		log.debug("LinkStorage:update(): {} {}", op, link);
-		
 		switch (op) {
 		case UPDATE:
 		case CREATE:
 		case INSERT:
-			addLink(link, linkinfo);
+			addOrUpdateLink(link, linkinfo, op);
 			break;
 		case DELETE:
+			deleteLink(link);
 			break;
 		}
 	}
 
-	protected void addLink(Link lt, LinkInfo linkinfo) {
-		Vertex vswSrc, vswDst;
+	private Vertex getPortVertex(String dpid, short port) {
+		Vertex vsw, vport = null;
+        if ((vsw = graph.getVertices("dpid", dpid).iterator().next()) != null) {
+        	GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();        	
+        	pipe.start(vsw).out("on").has("number", port);
+        	if (pipe.hasNext()) {
+        		vport = pipe.next();
+        	}
+        }
+        return vport;
+	}
+	
+	public void addOrUpdateLink(Link lt, LinkInfo linkinfo, DM_OPERATION op) {
 		Vertex vportSrc = null, vportDst = null;
 	
-		log.info("addLink(): {} {} getSrc {}", new Object[]{lt, linkinfo, lt.getSrc()});
+		log.debug("addOrUpdateLink(): op {} {} {}", new Object[]{op, lt, linkinfo});
 		
         try {
             // get source port vertex
         	String dpid = HexString.toHexString(lt.getSrc());
         	short port = lt.getSrcPort();
-            if ((vswSrc = graph.getVertices("dpid", dpid).iterator().next()) != null) {
-            	log.debug("addLink(): sw exists {} {}", dpid, vswSrc);
-            	GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
-            	
-            	//if (vswSrc.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().hasNext()) {
-            	pipe.start(vswSrc).out("on").has("number", port);
-            	//pipe.start(vswSrc).out("on");
-            	//log.debug("pipe count {}", pipe.count());
-            	if (pipe.hasNext()) {
-            		//vportSrc = vswSrc.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().next();
-            		vportSrc = pipe.next();
-            		log.debug("addLink(): port found {} {}", port, vportSrc);
-            	} else {
-            		log.error("addLink(): sw {} port {} not found", dpid, port);
-            	}
-            }
+        	vportSrc = getPortVertex(dpid, port);
             
             // get dest port vertex
             dpid = HexString.toHexString(lt.getDst());
             port = lt.getDstPort();
-            if ((vswDst = graph.getVertices("dpid",dpid).iterator().next()) != null) {
-            	log.debug("addLink(): sw exists {} {}", dpid, vswDst);
-            	GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
-            	pipe.start(vswDst).out("on").has("number", port);
-            	//if (vswDst.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().hasNext()) {
-            	if (pipe.hasNext()){
-            		//vportDst = vswDst.query().direction(Direction.OUT).labels("on").has("number",port).vertices().iterator().next();
-            		vportDst = pipe.next();
-            		log.debug("addLink(): port found {} {}", port, vportDst);
-            	} else {
-            		log.error ("addLink(): sw {} port {} not found", dpid, port);
-            	}
-            }
-            
+            vportDst = getPortVertex(dpid, port);
+                        
             if (vportSrc != null && vportDst != null) {
-            	//TODO: If Edge already exists should we remove and add again?
+            	
+            	// check if the link exists
             	List<Vertex> currLinks = new ArrayList<Vertex>();
             	for (Vertex V : vportSrc.query().direction(Direction.OUT).labels("link").vertices()) {
             		currLinks.add(V);
             	}
             	
             	if (currLinks.contains(vportDst)) {
-            	// if (vportSrc.query().direction(Direction.OUT).labels("link").vertices().iterator().hasNext() &&
-            	//	vportSrc.query().direction(Direction.OUT).labels("link").) {
-            		//FIXME: Succeed silently for now
-            		log.debug("addLink(): Failure: link exists {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
+            		// TODO: update linkinfo
+            		if (op.equals(DM_OPERATION.INSERT) || op.equals(DM_OPERATION.CREATE)) {
+            			log.debug("addOrUpdateLink(): Failure: link exists {} {} src {} dst {}", 
+            					new Object[]{op, lt, vportSrc, vportDst});
+            		}
             	} else {
             		graph.addEdge(null, vportSrc, vportDst, "link");
             		graph.stopTransaction(Conclusion.SUCCESS);
+            		log.debug("addOrUpdateLink(): link added {} {} src {} dst {}", new Object[]{op, lt, vportSrc, vportDst});
             	}
-        		log.debug("addLink(): link added {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
             } else {
-            	log.error("addLink(): failed {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
+            	log.error("addOrUpdateLink(): failed {} {} src {} dst {}", new Object[]{op, lt, vportSrc, vportDst});
             	graph.stopTransaction(Conclusion.FAILURE);
             }
         } catch (TitanException e) {
             /*
              * retry till we succeed?
              */
-        	log.error("addLink(): {} failed", lt);
+        	log.error("addOrUpdateLink(): failed {} {}", new Object[]{op, lt});
         }
 	}
 	
 	@Override
-	public List<Link> getLinks(Long dpid, int port) {
-		// TODO Auto-generated method stub
-		return null;
+	public void deleteLinks(List<Link> links) {
+
+		for (Link lt : links) {
+			deleteLink(lt);
+		}
 	}
+	
 
 	@Override
-	public void deleteLinks(Long dpid, int port) {
-		// TODO Auto-generated method stub
-
+	public void deleteLink(Link lt) {
+		Vertex vportSrc = null, vportDst = null;
+		int count = 0;
+		
+		log.debug("deleteLink(): {}", lt);
+		
+        try {
+            // get source port vertex
+         	String dpid = HexString.toHexString(lt.getSrc());
+         	short port = lt.getSrcPort();
+         	vportSrc = getPortVertex(dpid, port);
+            
+            // get dst port vertex
+         	dpid = HexString.toHexString(lt.getDst());
+         	port = lt.getDstPort();
+         	vportDst = getPortVertex(dpid, port);
+         	
+         	if (vportSrc != null && vportDst != null) {
+         		for (Edge e : vportSrc.getEdges(Direction.OUT)) {
+         			log.debug("deleteLink(): {} {}", e.getLabel(), e.getVertex(Direction.IN));
+         			// if (e.getLabel().equals("link") && e.getVertex(Direction.OUT).equals(vportDst)) {
+             		if (e.getLabel().equals("link")) {
+         				graph.removeEdge(e);
+         				count++;
+         			}
+         		}
+        		graph.stopTransaction(Conclusion.SUCCESS);
+            	log.debug("deleteLink(): {} {} src {} dst {}", new Object[]{
+            			(count > 0) ? "deleted " + count : "failure", lt, vportSrc, vportDst});
+            	
+            } else {
+            	log.error("deleteLink(): failed src port vertex not found {} src {} dst {}", new Object[]{lt, vportSrc, vportDst});
+            	graph.stopTransaction(Conclusion.FAILURE);
+            }
+         	
+        } catch (TitanException e) {
+            /*
+             * retry till we succeed?
+             */
+        	log.error("deleteLink(): {} failed", lt);
+        }
 	}
 
+	// TODO: Fix me
+	@Override
+	public List<Link> getLinks(Long dpid, short port) {
+		Vertex vportSrc, vportDst;
+    	List<Link> links = null;
+    	Link lt;
+    	
+		vportSrc = getPortVertex(HexString.toHexString(dpid), port);
+		if (vportSrc != null) {
+     		for (Edge e : vportSrc.getEdges(Direction.OUT)) {
+     			if (e.getLabel().equals("link")) {
+     				break;
+     			}
+     		}
+		}
+     	return null;
+	}
+	
 	@Override
 	public void init(String conf) {
 		//TODO extract the DB location from conf
@@ -155,4 +198,11 @@
         	graph.stopTransaction(Conclusion.SUCCESS);
         }
 	}
+
+	@Override
+	public void deleteLinksOnPort(Long dpid, short port) {
+		// TODO Auto-generated method stub
+		
+	}
+
 }
diff --git a/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImplTest.java b/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImplTest.java
index 1d0bd95..0324a51 100644
--- a/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImplTest.java
+++ b/src/test/java/net/floodlightcontroller/linkdiscovery/internal/LinkStorageImplTest.java
@@ -96,7 +96,7 @@
 	@Test
 	public void testGetLinks(){
 		//TODO Make sure this works when the implementation is written
-		List<Link> list = linkStorage.getLinks(Long.decode("0x0000000000000a01"), 2);
+		List<Link> list = linkStorage.getLinks(Long.decode("0x0000000000000a01"), (short)2);
 		
 		assertEquals(list.size(), 1);
 		
@@ -131,7 +131,7 @@
 	public void testDeleteLinks(){
 		//TODO Make sure this works when the implementation is written
 		
-		linkStorage.deleteLinks(Long.decode("0x0000000000000a01"), 2);
+		linkStorage.deleteLinksOnPort(Long.decode("0x0000000000000a01"), (short)2);
 		
 		//Test if it was deleted correctly with the Gremlin API
 		GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>();
diff --git a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
index 59e0a51..ffabf6f 100644
--- a/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
+++ b/src/test/java/net/floodlightcontroller/util/OFMessageDamperMockSwitch.java
@@ -346,4 +346,10 @@
         return 0;
     }
 
+	@Override
+	public void setupRemoteSwitch(Long dpid) {
+		// TODO Auto-generated method stub
+		
+	}
+
 }
\ No newline at end of file