package io.lumify.core.model.workspace.diff;

import io.lumify.core.model.user.UserRepository;
import io.lumify.core.model.workspace.Workspace;
import io.lumify.core.model.workspace.WorkspaceEntity;
import io.lumify.core.model.workspace.WorkspaceRepository;
import io.lumify.core.user.User;
import io.lumify.core.util.GraphUtil;
import org.securegraph.*;
import com.google.inject.Inject;

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

import static org.securegraph.util.IterableUtils.toList;

public class WorkspaceDiff {
    private final Graph graph;
    private final UserRepository userRepository;

    @Inject
    public WorkspaceDiff(
            final Graph graph,
            final UserRepository userRepository) {
        this.graph = graph;
        this.userRepository = userRepository;
    }

    public List<DiffItem> diff(Workspace workspace, List<WorkspaceEntity> workspaceEntities, List<Edge> workspaceEdges, User user) {
        Authorizations authorizations = userRepository.getAuthorizations(user, WorkspaceRepository.VISIBILITY_STRING, workspace.getId());

        List<DiffItem> result = new ArrayList<DiffItem>();
        for (WorkspaceEntity workspaceEntity : workspaceEntities) {
            List<DiffItem> entityDiffs = diffWorkspaceEntity(workspace, workspaceEntity, authorizations);
            if (entityDiffs != null) {
                result.addAll(entityDiffs);
            }
        }

        for (Edge workspaceEdge : workspaceEdges) {
            List<DiffItem> entityDiffs = diffEdge(workspace, workspaceEdge, authorizations);
            if (entityDiffs != null) {
                result.addAll(entityDiffs);
            }
        }

        return result;
    }

    private List<DiffItem> diffEdge(Workspace workspace, Edge edge, Authorizations authorizations) {
        List<DiffItem> result = new ArrayList<DiffItem>();

        SandboxStatus sandboxStatus = GraphUtil.getSandboxStatus(edge, workspace.getId());
        if (sandboxStatus != SandboxStatus.PUBLIC) {
            result.add(new EdgeDiffItem(edge, sandboxStatus));
        }

        diffProperties(workspace, edge, result);

        return result;
    }

    public List<DiffItem> diffWorkspaceEntity(Workspace workspace, WorkspaceEntity workspaceEntity, Authorizations authorizations) {
        List<DiffItem> result = new ArrayList<DiffItem>();

        Vertex entityVertex = this.graph.getVertex(workspaceEntity.getEntityVertexId(), authorizations);

        // vertex can be null if the user doesn't have access to the entity
        if (entityVertex == null) {
            return null;
        }

        SandboxStatus sandboxStatus = GraphUtil.getSandboxStatus(entityVertex, workspace.getId());
        if (sandboxStatus != SandboxStatus.PUBLIC) {
            result.add(new VertexDiffItem(entityVertex, sandboxStatus, workspaceEntity.isVisible()));
        }

        diffProperties(workspace, entityVertex, result);

        return result;
    }

    private void diffProperties(Workspace workspace, Element element, List<DiffItem> result) {
        List<Property> properties = toList(element.getProperties());
        SandboxStatus[] propertyStatuses = GraphUtil.getPropertySandboxStatuses(properties, workspace.getId());
        for (int i = 0; i < properties.size(); i++) {
            if (propertyStatuses[i] != SandboxStatus.PUBLIC) {
                Property property = properties.get(i);
                Property existingProperty = findExistingProperty(properties, property);
                result.add(new PropertyDiffItem(element, property, existingProperty, propertyStatuses[i]));
            }
        }
    }

    private Property findExistingProperty(List<Property> properties, Property workspaceProperty) {
        for (Property property : properties) {
            if (property.getName().equals(workspaceProperty.getName())) {
                if (property.getKey().equals(workspaceProperty.getKey())) {
                    continue;
                }
                return property;
            }
        }
        return null;
    }
}

@@ -39,16 +39,49 @@
 .diff;%0A%0A
+import com.google.inject.Inject;%0A
 import i
@@ -384,41 +384,8 @@
 h.*;
-%0Aimport com.google.inject.Inject;
 %0A%0Aim
@@ -3482,16 +3482,34 @@
 perties,
+ propertyStatuses,
  propert
@@ -3512,16 +3512,16 @@
 perty);%0A
-
         
@@ -3719,16 +3719,50 @@
 perties,
+ SandboxStatus%5B%5D propertyStatuses,
  Propert
@@ -3797,16 +3797,69 @@
    for (
+int i = 0; i %3C properties.size(); i++) %7B%0A            
 Property
@@ -3868,17 +3868,17 @@
 roperty 
-:
+=
  propert
@@ -3876,27 +3876,32 @@
 = properties
-) %7B
+.get(i);
 %0A           
@@ -3959,19 +3959,16 @@
 tName())
-) %7B
 %0A       
@@ -3968,36 +3968,39 @@
                 
-if (
+    && 
 property.getKey(
@@ -4035,19 +4035,16 @@
 etKey())
-) %7B
 %0A       
@@ -4060,35 +4060,57 @@
     
-continue;%0A                %7D
+&& propertyStatuses%5Bi%5D == SandboxStatus.PUBLIC) %7B
 %0A   

find the correct existing property