package com.tinkerpop.gremlin;

import com.tinkerpop.gremlin.structure.Graph.Features.EdgeFeatures;
import com.tinkerpop.gremlin.structure.Graph.Features.EdgePropertyFeatures;
import com.tinkerpop.gremlin.structure.Graph.Features.VertexFeatures;
import com.tinkerpop.gremlin.structure.Graph.Features.VertexPropertyFeatures;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;

import static com.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_DOUBLE_VALUES;
import static com.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_FLOAT_VALUES;
import static com.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_INTEGER_VALUES;
import static com.tinkerpop.gremlin.structure.Graph.Features.DataTypeFeatures.FEATURE_STRING_VALUES;

/**
 * Annotations to define a graph example to load from test resources prior to test execution.  This annotation is
 * for use only with test that extend from {@link AbstractGremlinTest}.
 *
 * @author Stephen Mallette (http://stephen.genoprime.com)
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LoadGraphWith {

    public enum GraphData {
        /**
         * Loads the "classic" TinkerPop toy graph.
         */
        CLASSIC,

        /**
         * Loads the "classic" TinkerPop toy graph with the "weight" value on edges stored as double.  This should
         * be the most commonly used graph instance for testing as graphs that support string, double and int should
         * comprise the largest number of implementations.
         */
        CLASSIC_DOUBLE,

        /**
         * Loads the "grateful dead" graph which is a "large" graph which provides for the construction of more
         * complex traversals.
         */
        GRATEFUL;

        private static final List<FeatureRequirement> featuresRequiredByClassic = new ArrayList<FeatureRequirement>(){{
            add(FeatureRequirement.Factory.create(VertexFeatures.FEATURE_ADD_VERTICES, VertexFeatures.class));
            add(FeatureRequirement.Factory.create(EdgeFeatures.FEATURE_ADD_EDGES, EdgeFeatures.class));
            add(FeatureRequirement.Factory.create(FEATURE_STRING_VALUES, VertexPropertyFeatures.class));
            add(FeatureRequirement.Factory.create(FEATURE_INTEGER_VALUES, VertexPropertyFeatures.class));
            add(FeatureRequirement.Factory.create(FEATURE_FLOAT_VALUES, EdgePropertyFeatures.class));
        }};

        private static final List<FeatureRequirement> featuresRequiredByClassicDouble = new ArrayList<FeatureRequirement>(){{
            add(FeatureRequirement.Factory.create(VertexFeatures.FEATURE_ADD_VERTICES, VertexFeatures.class));
            add(FeatureRequirement.Factory.create(EdgeFeatures.FEATURE_ADD_EDGES, EdgeFeatures.class));
            add(FeatureRequirement.Factory.create(FEATURE_STRING_VALUES, VertexPropertyFeatures.class));
            add(FeatureRequirement.Factory.create(FEATURE_INTEGER_VALUES, VertexPropertyFeatures.class));
            add(FeatureRequirement.Factory.create(FEATURE_DOUBLE_VALUES, EdgePropertyFeatures.class));
        }};

        private static final List<FeatureRequirement> featuresRequiredByGrateful = new ArrayList<FeatureRequirement>() {{
            add(FeatureRequirement.Factory.create(VertexFeatures.FEATURE_ADD_VERTICES, VertexFeatures.class));
            add(FeatureRequirement.Factory.create(EdgeFeatures.FEATURE_ADD_EDGES, EdgeFeatures.class));
            add(FeatureRequirement.Factory.create(FEATURE_STRING_VALUES, VertexPropertyFeatures.class));
            add(FeatureRequirement.Factory.create(FEATURE_INTEGER_VALUES, VertexPropertyFeatures.class));
        }};

        public String location() {
            switch (this) {
                case CLASSIC:
                    return RESOURCE_PATH_PREFIX + "tinkerpop-classic.gio";
                case CLASSIC_DOUBLE:
                    return RESOURCE_PATH_PREFIX + "tinkerpop-classic-double.gio";
                case GRATEFUL:
                    return RESOURCE_PATH_PREFIX + "grateful-dead.gio";
            }

            throw new RuntimeException("No file for this GraphData type");
        }

        public List<FeatureRequirement> featuresRequired() {
            switch (this) {
                case CLASSIC:
                    return featuresRequiredByClassic;
                case CLASSIC_DOUBLE:
                    return featuresRequiredByClassicDouble;
                case GRATEFUL:
                    return featuresRequiredByGrateful;
            }

            throw new RuntimeException("No features for this GraphData type");
        }
    }

    public static final String RESOURCE_PATH_PREFIX = "/com/tinkerpop/gremlin/structure/util/io/kryo/";

    /**
     * The name of the resource to load with full path.
     */
    public GraphData value() default GraphData.CLASSIC;

}

@@ -87,154 +87,16 @@
 Edge
-Features;%0Aimport com.tinkerpop.gremlin.structure.Graph.Features.EdgePropertyFeatures;%0Aimport com.tinkerpop.gremlin.structure.Graph.Features.Vertex
+Property
 Feat
@@ -1027,16 +1027,739 @@
 nTest%7D.%0A
+ * %3Cbr/%3E%0A * Note that the annotation assumes that the @%7Blink GraphData%7D referenced by the annotation can be made available%0A * to the graph in the test.  In other words, even a graph that has %22read-only%22 features, should have some method of%0A * getting the data available to it.  That said, graphs must minimally support the data types that the sample%0A * data contains for the test to be executed.%0A * %3Cbr/%3E%0A * If a graph implementation is %22read-only%22, it can override the%0A * %7B@link GraphProvider#loadGraphData(com.tinkerpop.gremlin.structure.Graph, LoadGraphWith)%7D method to provide some%0A * other mechanism for making that data available to the graph in time for the test.  See the Giraph implementation%0A * for more details.%0A
  *%0A * @a
@@ -2698,223 +2698,8 @@
 )%7B%7B%0A
-            add(FeatureRequirement.Factory.create(VertexFeatures.FEATURE_ADD_VERTICES, VertexFeatures.class));%0A            add(FeatureRequirement.Factory.create(EdgeFeatures.FEATURE_ADD_EDGES, EdgeFeatures.class));%0A
     
@@ -3150,223 +3150,8 @@
 )%7B%7B%0A
-            add(FeatureRequirement.Factory.create(VertexFeatures.FEATURE_ADD_VERTICES, VertexFeatures.class));%0A            add(FeatureRequirement.Factory.create(EdgeFeatures.FEATURE_ADD_EDGES, EdgeFeatures.class));%0A
     
@@ -3465,32 +3465,32 @@
 );%0A        %7D%7D;%0A%0A
+
         private 
@@ -3599,223 +3599,8 @@
  %7B%7B%0A
-            add(FeatureRequirement.Factory.create(VertexFeatures.FEATURE_ADD_VERTICES, VertexFeatures.class));%0A            add(FeatureRequirement.Factory.create(EdgeFeatures.FEATURE_ADD_EDGES, EdgeFeatures.class));%0A
     

Update the semantics of the LoadGraphWith annotation.