/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.onrc.onos.ofcontroller.flowmanager;

import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.Edge;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.onrc.onos.graph.DBOperation;
import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IBaseObject;
import com.tinkerpop.blueprints.impls.ramcloud.RamCloudGraph;
import com.tinkerpop.blueprints.impls.ramcloud.RamCloudVertex;
import java.util.List;
import java.util.Set;

/**
 *
 * @author nickkaranatsios
 */
public class FlowEntity implements FlowEntityManager {
    private String primaryKey;
    // TODO: Should remove since not implemented.
    private Class<?> hasMany;
    private Collection<?> many = new ArrayList<>();
    private Map<String, Object> properties;
    private Map<String, Map<String, Object>> operations = new HashMap<>();
    private ArrayList<Object> children = new ArrayList<>();
    private ArrayList<Object> edges = new ArrayList<>();
    private int opCount;
    public Direction dir;

    public FlowEntity() {
        opCount = 0;
    }
    
    private class EntityEdge {
        private Object src;
        private Object dst;
        private Direction dir;
        private String label;
        private DBOperationType op;
        
        public EntityEdge(Object src, Object dst, DBOperationType op, Direction dir, String label) {
            this.src = src;
            this.dst = dst;
            this.dir = dir;
            this.label = label;
            this.op = op;
        }
        
        public EntityEdge(Object src, Object dst, String label) {
            this.src = src;
            this.dst = dst;
            this.label = label;
        }
        
        @Override
        public String toString() {
            return "EntityEdge: " + src + " " + dst + " " + label;
        }
    }

    private class RamCloudEdgeEntity implements Edge {
        private Vertex src;
        private Vertex dst;
        private Direction direction;
        private String label;

        public RamCloudEdgeEntity(Vertex src, Vertex dst, Direction direction, String label) {
            this.src = src;
            this.dst = dst;
            this.direction = direction;
            this.label = label;
        }
        
        @Override
        public Vertex getVertex(com.tinkerpop.blueprints.Direction dir) throws IllegalArgumentException {
            if (dir == Direction.IN) {
                return dst;
            } else if (dir == Direction.OUT) {
                return src;
            }
            return null;
        }

        @Override
        public String getLabel() {
            return this.label;
        }

        @Override
        public <T> T getProperty(String key) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public Set<String> getPropertyKeys() {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public void setProperty(String key, Object value) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public <T> T removeProperty(String key) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public Object getId() {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }
        
    }
    
    @Override
    public void setPrimaryKey(String key) {
        primaryKey = key;
    }
    
    @Override
    public String getPrimaryKey() {
        return primaryKey;
    }

    @Override
    public void hasMany(Class<?> cClass) {
        hasMany = cClass;
    }
    
    @Override
    public void operationBegin(String opName) {
        properties = new HashMap<>();
        operations.put(getOpKey(opName), properties);
        opCount++;
    }
    
    @Override
    public void operationEnd(String opName) {
        // TODO: This method is implemented in case we need to reset any variables.
        /*
        String opKey = getOpKey(opName);
        if (operations.containsKey(opKey)) {
            System.out.println(operations);
        }
        */
    }
    
    
    private String getOpKey(String opName) {
        return opName + new Integer(opCount).toString();
        
    }

    @Override
    public void setProperty(String propertyName, Object value) {
        properties.put(propertyName, value);
    }

    @Override
    public FlowEntityManager append(Object entity) {
        children.add(entity);
        return this;
    }
    
    @Override
    public Object getProperty(String propertyName) {
        if (properties.containsKey(propertyName)) {
            return properties.get(propertyName);
        }
        return null;
    }
    
    @Override
    public void persist(DBOperation dbHandler) {
        // get a hold of all the flow entries for the current flowpath.
        if (children.size() > 0) {
            int noOfChildren = children.size();
            if (noOfChildren > 0) {
                // construct a list of null ids for creating vertices for all
                // flow entries.
                ArrayList<Object> ids = new ArrayList<>(noOfChildren);
                // set properties
                Map<RamCloudVertex, Map<String, Object>> propertiesToSet = new HashMap<>();
                
                RamCloudGraph graph = (RamCloudGraph)dbHandler.getDBConnection().getFramedGraph().getBaseGraph();
                for (int i = 0; i < noOfChildren; i++) {
                    ids.add(null);
                }
                List<RamCloudVertex> addedVertices = graph.addVertices(ids);
                //Iterable<Vertex> vertices = dbHandler.setVertices(ids);
                //Iterator vi = vertices.iterator();
                // get source and destination edge match vertex v construct list
                // of edges
                ArrayList<Edge> edgesToSet = new ArrayList<>();
                for (int i = 0; i < noOfChildren; i++) {
                    FlowEntity childEntity = (FlowEntity)children.get(i);
                    Vertex srcVertex = addedVertices.get(i);                    
                    propertiesToSet.put((RamCloudVertex)srcVertex, childEntity.properties);

                    if (srcVertex == null) continue;
                    for (int j = 0; j < childEntity.edges.size(); j++) {
                        EntityEdge edge = (EntityEdge) childEntity.edges.get(j);
                        edgesToSet.add(new RamCloudEdgeEntity(srcVertex, ((IBaseObject) edge.dst).asVertex(), edge.dir, edge.label));
                    }
                }
                graph.addEdges(edgesToSet);
                graph.setProperties(propertiesToSet);
            }
        }
    }

    private Vertex getVertexEdge(Iterator vi, int idx) {
        int i = 0;
        while (vi.hasNext()) {
            Vertex v = (Vertex)vi.next();
            if (i == idx) {
                return v;
            }
            i++;
        }
        return null;
    }
    
    @Override
    public Map<String, Object> getProperties() {
        return properties;
    }
    
    @Override
    public void addEdge(Object dst, Direction dir, String label) {
        edges.add(new EntityEdge(this, dst, DBOperationType.ADD, dir, label));
    }
    
    @Override
    public void removeEdge(Object src, Object dst, Direction dir, String label) {
        edges.add(new EntityEdge(src, dst, DBOperationType.REMOVE, dir, label));
    }
}
