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.Node;
import org.iri_research.renkan.models.NodeStyle;
import org.iri_research.renkan.models.Project;
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;
import org.springframework.data.mongodb.core.geo.Point;

@Named
public class NodeSyncEventManager extends
        AbstractSyncEventManager<Node, String> {

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

    @Inject
    private NodesRepository nodesRepository;

    @Inject
    private UsersRepository usersRepository;

    public NodesRepository getNodesRepository() {
        return nodesRepository;
    }

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

    public UsersRepository getUsersRepository() {
        return this.usersRepository;
    }

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

        // get project
        this.logger.debug("NodeSyncEventManager: insert Node");

        @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("node insert: project not found",
                    String.format("Project %s not found", project_id));
        }

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

        @SuppressWarnings("unchecked")
        Map<String, Object> positionValues = (Map<String, Object>) values
                .get("position");

        Point nodePosition = new Point(
                ((Number) positionValues.get("x")).doubleValue(),
                ((Number) positionValues.get("y")).doubleValue());

        String image = (String) values.get("image");

        String node_id = (String) values.get("id");

        //check that node id is unique
        if(this.getNodesRepository().exists(node_id)) {
            throw new CowebException("node insert: node exists",
                    String.format("node %s already exists", node_id));
         }


        Integer size = (Integer) values.get("size");

        String shape = (String) values.get("shape");
        String type = (String) values.get("type");
        Boolean hidden = (Boolean) values.get("hidden");
        
        @SuppressWarnings("unchecked")
        Map<String, Object> styleValues = (Map<String, Object>) data.get("style");
        
        NodeStyle style = null; 
        if(null != styleValues) {
            style = new NodeStyle((String)styleValues.get("color"), (Boolean)styleValues.get("dash"), (Integer)styleValues.get("thickness"));
        }



        Node node = new Node(node_id, (String) values.get("title"),
                (String) values.get("description"), (String) values.get("uri"),
                style, creator_id, nodePosition, image,
                size, shape, type, hidden, project_id);

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

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

        this.getNodesRepository().save(node);
        this.getProjectsRepository().save(project);

    }

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

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

    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 node_id = (String) values.get("id");

        Node node = this.getNodesRepository().findOne(node_id);

        if(node==null) {
            return true;
        }
        else if ( (project_id == node.getProjectId()) || (project_id != null && project_id.equals(node.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 node","Node not in correct project");
        }
    }

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


}
