package org.iri_research.renkan.coweb.event;

import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;

import org.coweb.CowebException;
import org.iri_research.renkan.models.Edge;
import org.iri_research.renkan.models.EdgeStyle;
import org.iri_research.renkan.models.Node;
import org.iri_research.renkan.models.Project;
import org.iri_research.renkan.repositories.EdgesRepository;
import org.iri_research.renkan.repositories.IRenkanRepository;
import org.iri_research.renkan.repositories.NodesRepository;
import org.iri_research.renkan.repositories.UsersRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Named
public class EdgeSyncEventManager extends
        AbstractSyncEventManager<Edge, String> {

    private final Logger logger = LoggerFactory
            .getLogger(EdgeSyncEventManager.class);

    @Inject
    private NodesRepository nodesRepository;

    @Inject
    private UsersRepository usersRepository;

    @Inject
    private EdgesRepository edgesRepository;

    public NodesRepository getNodesRepository() {
        return nodesRepository;
    }

    public UsersRepository getUsersRepository() {
        return usersRepository;
    }

    public EdgesRepository getEdgesRepository() {
        return edgesRepository;
    }

    @Override
    public IRenkanRepository<Edge, String> getObjectRepository() {
        return this.getEdgesRepository();
    }

    @Override
    public void insert(String clientId, Map<String, Object> data) {

        // get project
        this.logger.debug("EdgeSyncEventManager: insert Edge");

        @SuppressWarnings("unchecked")
        Map<String, Object> values = (Map<String, Object>) data.get("value");
        String project_id = (String) values.get("_project_id");

        Project project = this.getProjectsRepository().findOne(project_id);

        if (null == project) {
            throw new CowebException("Edge insert: project not found",
                    String.format("Project %s not found", project_id));
        }

        String creator_id = (String) values.get("created_by");

        String from_node_id = (String) values.get("from");
        Node from_node = this.getNodesRepository().findOne(from_node_id);

        if (null == from_node) {
            throw new CowebException("Edge insert: from not found",
                    String.format("from %s not found", from_node_id));
        }

        String to_node_id = (String) values.get("to");
        Node to_node = this.getNodesRepository().findOne(to_node_id);

        if (null == to_node) {
            throw new CowebException("Edge insert: to not found",
                    String.format("to %s not found", to_node_id));
        }

        String edge_id = (String) values.get("id");
        
        @SuppressWarnings("unchecked")
        Map<String, Object> styleValues = (Map<String, Object>) data.get("style");
        
        EdgeStyle style = null; 
        if(null != styleValues) {
            style = new EdgeStyle((String)styleValues.get("color"), (Boolean)styleValues.get("dash"), (Integer)styleValues.get("thickness"), (Boolean)styleValues.get("arrow"));
        }
        
        //check that edge id is unique
        if(this.getEdgesRepository().exists(edge_id)) {
            throw new CowebException("edge insert: edge exists",
                    String.format("Edge %s already exists", edge_id));
         }

        Edge edge = new Edge(edge_id, (String) values.get("title"),
                (String) values.get("description"), (String) values.get("uri"),
                style, from_node, to_node, creator_id,
                project_id);

        Integer position = (Integer) data.get("position");

        if (position == null || position < 0) {
            throw new CowebException("Edge insert: bad insert position",
                    String.format("Bad position %s not found",
                            position == null ? "null" : position.toString()));
        }
        int index = position.intValue();
        List<Edge> edges = project.getEdges();
        if (index > edges.size()) {
            index = edges.size();
        }
        edges.add(index, edge);

        this.getEdgesRepository().save(edge);
        this.getProjectsRepository().save(project);

    }

    @Override
    public void nullOperation(String clientId, Map<String, Object> data) {
        this.logger.debug("nullOperation: NOP");
    }

    @Override
    protected List<Edge> getObjectList(Project project) {
        return project.getEdges();
    }

    private boolean checkWrite(String clientId, Map<String, Object> data) {

        @SuppressWarnings("unchecked")
        Map<String, Object> values = (Map<String, Object>) data.get("value");
        String project_id = (String) values.get("_project_id");

        String edge_id = (String) values.get("id");
        
        Edge edge = this.getEdgesRepository().findOne(edge_id);
        
        if(edge==null) {
            return true;
        }
        else if ( (project_id == edge.getProjectId()) || (project_id != null && project_id.equals(edge.getProjectId()))) {
            return true;
        }
        else {
            return false;
        }
    }
    
    @Override
    protected void checkUpdate(String clientId, Map<String, Object> data) {

        if(!checkWrite(clientId, data)) {
            throw new CowebException("Error when updating edge","Edge not in correct project");
        }
    }

    @Override
    protected void checkDelete(String clientId, Map<String, Object> data) {
        if(!checkWrite(clientId, data)) {
            throw new CowebException("Error when updating edge","Edge not in correct project");
        }
    }

}
