package org.umlg.sqlg.sql.parse;

import com.google.common.base.Preconditions;
import org.apache.tinkerpop.gremlin.structure.Element;
import org.umlg.sqlg.structure.SchemaTable;
import org.umlg.sqlg.structure.SqlgGraph;
import org.umlg.sqlg.util.SqlgUtil;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Date: 2015/01/03
 * Time: 1:06 PM
 */
public class GremlinParser<S extends Element, E extends Element> {

    private SqlgGraph sqlgGraph;

    public GremlinParser(SqlgGraph sqlgGraph) {
        this.sqlgGraph = sqlgGraph;
    }

    public Set<SchemaTableTree> parseForStrategy(List<ReplacedStep<S, E>> replacedSteps) {
        ReplacedStep startReplacedStep = replacedSteps.get(0);
        Set<SchemaTableTree> result = parse(replacedSteps);
        replacedSteps.add(0, startReplacedStep);
        return result;
    }

    /**
     * This is for the GraphStep
     * The first replacedStep has the starting SchemaTable.
     * @param replacedSteps
     * @return
     */
    public Set<SchemaTableTree> parse(List<ReplacedStep<S, E>> replacedSteps) {
        ReplacedStep startReplacedStep = replacedSteps.remove(0);
        Preconditions.checkState(startReplacedStep.isGraphStep(), "Step must be a GraphStep");
        Set<SchemaTableTree> rootSchemaTableTrees = startReplacedStep.getRootSchemaTableTrees(this.sqlgGraph, replacedSteps.size());
        Set<SchemaTableTree> toRemove = new HashSet<>();
        for (SchemaTableTree rootSchemaTableTree : rootSchemaTableTrees) {
            SqlgUtil.removeTopologyStrategyHasContainer(rootSchemaTableTree.getHasContainers());
            Set<SchemaTableTree> schemaTableTrees = new HashSet<>();
            schemaTableTrees.add(rootSchemaTableTree);
            for (ReplacedStep<S, E> replacedStep : replacedSteps) {
                //This schemaTableTree represents the tree nodes as build up to this depth. Each replacedStep goes a level further
                schemaTableTrees = replacedStep.calculatePathForStep(schemaTableTrees);
            }
            boolean remove = rootSchemaTableTree.removeNodesInvalidatedByHas();
            if (remove) {
                toRemove.add(rootSchemaTableTree);
            }
            rootSchemaTableTree.removeAllButDeepestLeafNodes(replacedSteps.size());
        }
        rootSchemaTableTrees.removeAll(toRemove);
        return rootSchemaTableTrees;

    }

    /**
     * This is only called for local vertex steps.
     * Constructs the label paths from the given schemaTable to the leaf vertex labels for the gremlin query.
     * For each path Sqlg will executeRegularQuery a sql query. The union of the queries is the result the gremlin query.
     * The vertex labels can be calculated from the steps.
     *
     * @param schemaTable
     * @param replacedSteps The original VertexSteps and HasSteps that were replaced
     * @return a List of paths. Each path is itself a list of SchemaTables.
     */
    public SchemaTableTree parse(SchemaTable schemaTable, List<ReplacedStep<S, E>> replacedSteps) {
        if (replacedSteps.get(0).isGraphStep()) {
            throw new IllegalStateException("is this really still firing!!!");
        } else {
            Set<SchemaTableTree> schemaTableTrees = new HashSet<>();
            //replacedSteps contains a fake label representing the incoming vertex for the SqlgVertexStepStrategy.
            SchemaTableTree rootSchemaTableTree = new SchemaTableTree(this.sqlgGraph, schemaTable, 0, replacedSteps.size() - 1);
            rootSchemaTableTree.setOptionalLeftJoin(replacedSteps.get(0).isLeftJoin());
            rootSchemaTableTree.setEmit(replacedSteps.get(0).isEmit());
            rootSchemaTableTree.setUntilFirst(replacedSteps.get(0).isUntilFirst());
            rootSchemaTableTree.initializeAliasColumnNameMaps();
            //TODO what about the emit, untilFirst flag????
            rootSchemaTableTree.setStepType(schemaTable.isVertexTable() ? SchemaTableTree.STEP_TYPE.VERTEX_STEP : SchemaTableTree.STEP_TYPE.EDGE_VERTEX_STEP);
            schemaTableTrees.add(rootSchemaTableTree);
            for (ReplacedStep<S, E> replacedStep : replacedSteps) {
                if (!replacedStep.isFake()) {
                    //This schemaTableTree represents the tree nodes as build up to this depth. Each replacedStep goes a level further
                    schemaTableTrees = replacedStep.calculatePathForStep(schemaTableTrees);
                }
            }
            rootSchemaTableTree.removeAllButDeepestLeafNodes(replacedSteps.size() - 1);
            rootSchemaTableTree.removeNodesInvalidatedByHas();
            rootSchemaTableTree.setLocalStep(true);
            return rootSchemaTableTree;
        }
    }

}

@@ -954,16 +954,23 @@
 aTable.%0A
+     *%0A
      * @
@@ -2254,32 +2254,43 @@
 oveAllButDeepest
+AndAddCache
 LeafNodes(replac
@@ -3071,20 +3071,45 @@
         
-if (
+Preconditions.checkArgument(!
 replaced
@@ -3138,117 +3138,60 @@
 ep()
-) %7B%0A            throw new IllegalStateException(%22is this really still firing!!!%22);%0A        %7D else %7B%0A 
+, %22Expected VertexStep, found GraphStep%22);%0A%0A
         
    S
@@ -3178,35 +3178,32 @@
 tep%22);%0A%0A        
-   
 Set%3CSchemaTableT
@@ -3251,20 +3251,16 @@
         
-   
- 
 //replac
@@ -3354,20 +3354,16 @@
 rategy.%0A
-    
         
@@ -3479,36 +3479,32 @@
 ) - 1);%0A        
- 
-   
 rootSchemaTableT
@@ -3563,36 +3563,32 @@
 oin());%0A        
-   
- 
 rootSchemaTableT
@@ -3627,28 +3627,24 @@
 .isEmit());%0A
-    
         root
@@ -3711,36 +3711,32 @@
 rst());%0A        
- 
-   
 rootSchemaTableT
@@ -3776,72 +3776,8 @@
 ();%0A
-            //TODO what about the emit, untilFirst flag????%0A    
     
@@ -3927,20 +3927,16 @@
 _STEP);%0A
-    
         
@@ -3978,36 +3978,32 @@
 eTree);%0A        
-    
 for (ReplacedSte
@@ -4050,28 +4050,24 @@
             
-    
 if (!replace
@@ -4080,28 +4080,24 @@
 isFake()) %7B%0A
-    
             
@@ -4223,36 +4223,32 @@
                 
-    
 schemaTableTrees
@@ -4319,32 +4319,20 @@
     
-    %7D%0A            
 %7D%0A    
+    %7D%0A
     
@@ -4365,125 +4365,128 @@
 move
-AllButDeepestLeafNodes(replacedSteps.size() - 1);%0A            rootSchemaTableTree.removeNodesInvalidatedByHas();%0A    
+NodesInvalidatedByHas();%0A        rootSchemaTableTree.removeAllButDeepestAndAddCacheLeafNodes(replacedSteps.size() - 1);%0A
     
@@ -4533,28 +4533,24 @@
 e);%0A        
-    
 return rootS
@@ -4565,26 +4565,16 @@
 leTree;%0A
-        %7D%0A
     %7D%0A%0A%7D

fix issue 63, need to remove invalid nodes before calculating the leafNodes, else invalid nodes remain cached in the tree.