using System;
using System.Collections.Generic;
using edu.neu.ccs.demeterf.util;
using edu.neu.ccs.demeterf.control;

namespace edu.neu.ccs.demeterf{

    public abstract class Control{
        public Control(){ foreach(Type t in Util.builtInTypes)builtInList.Add(t); }

        /** Returns an immutable Control that permits the Everywhere Traversal */
        public static Control everywhere(){ return new Everywhere(); }
        /** Returns an immutable Control that permits the OneStep Traversal */
        public static Control nowhere(){ return new Nowhere(); }
        /** Returns a mutable Control with the given Classes as BuiltIns */
        public static MutableControl builtins(params Type[] ts){
            MutableControl ec = bypass(new Edge[0]);
            foreach(Type t in ts)ec.addBuiltIn(t);
            return ec;
        }

        /** Returns a mutable Control that bypasses the given Edges */
        public static MutableControl bypass(params Edge[] edges){ return new EdgeBypass(edges); }
        /** Returns a mutable Control that bypasses the edges given in the string. Edges
         *    are of the form: "Class1.field Class2.field ...".  Full package names may
         *    be used, or Type.addPath(...) can be used to add a package to the class
         *    lookup path*/
        /** C#!!  When you are using a namespace qualified type that is compiled into a
         *          separate library, the order of the names is a little backwards:
         *              Namespace.Name.Type+Inner,Assembly.Name.Field
         *
         *  E.g.,  "ccs.neu.edu.demeterf.lib.Cons,DemeterF.firstF"
         *
         */ 
        public static MutableControl bypass(String s){ return new EdgeBypass(s); }
        /** Same as bypassing(String) but the first is a package in which to search
         *    for classes */
        public static MutableControl bypass(String pkg, String s){ return new EdgeBypass(pkg,s); }
        /** Returns a mutable Control that bypasses all the Edges of the given classes */
        public static MutableControl bypass(params Type[] cs){ return new EdgeBypass(cs); }
    
    

        /** Returns a mutable Control that only traverses the given Edges */
        public static MutableControl only(params Edge[] edges){ return new EdgeOnly(edges); }
        /** Returns a mutable Control that only traverses the edges given in the string. Edges
         *    are of the form: "Class1.field Class2.field ...".  Full package names may
         *    be used, or Type.addPath(...) can be used to add a package to the class
         *    lookup path*/
        public static MutableControl only(String s){ return new EdgeOnly(s); }
        /** Same as only(String) but the first is a package in which to search
         *    for classes */
        public static MutableControl only(String pkg, String s){ return new EdgeOnly(pkg,s); }
        /** Returns a mutable Control that only traverses the Edges of the given classes */
        public static MutableControl only(params Type[] cs){ return new EdgeOnly(cs); }
    
        /** Returns a mutable Control that ignores the given Edges */
        public static MutableControl remove(params Edge[] edges){ return new EdgeRemove(edges); }
        /** Returns a mutable Control that ignores the edges given in the string. Edges
         *    are of the form: "Class1.field Class2.field ...".  Full package names may
         *    be used, or Type.addPath(...) can be used to add a package to the class
         *    lookup path*/
        public static MutableControl remove(String s){ return new EdgeRemove(s); }
        /** Same as remove(String) but the first is a package in which to search
         *    for classes */
        public static MutableControl remove(String pkg, String s){ return new EdgeRemove(pkg,s); }
        /** Returns a mutable Control that ignores all the Edges of the given classes */
        public static MutableControl remove(params Type[] cs){ return new EdgeRemove(cs); }    
        // List of Primitive Classes
        protected List<Type> builtInList = new List<Type>();
        // Returns whether or not tthe given Class is a Builtin
        public bool isBuiltIn(Type t){ return builtInList.Contains(t); }
    
        // Returns whether or not to bypass the given Class/Field
        public abstract bool skip(Type c, String f);
        // Returns whether or not to bypass the given Edge
        public abstract bool skip(Edge e);

        /** Returns whether or not to bypass/skip the given Class/Field */
        public abstract bool ignore(Type c, String f);
        /** Returns whether or not to bypass/skip the given Edge */
        public abstract bool ignore(Edge e);
    }
}