package edu.neu.ccs.demeterf;

import java.util.HashSet;

//import edu.neu.ccs.demeter.dj.ClassGraph;
import edu.neu.ccs.demeterf.control.*;
import edu.neu.ccs.demeterf.util.Util;

/** Base Control Class, supports the implementation of immutable (and mutable)
 *    traversal Control classes.  Implements static methods that create both
 *    kinds of control for the usual needs.
 */
public abstract class Control{
    /** Returns an immutable Control that permits the Everywhere Traversal */
    public static Control everywhere(){ return new Everywhere(); }
    /** Returns an immutable Control that permits a one-step Traversal */
    public static Control nowhere(){ return new Nowhere(); }
    /** Returns a mutable MutableControl with the given Classes as BuiltIns */
    public static MutableControl builtins(Class<?> ... cls){
        MutableControl ec = new EdgeBypass(new Edge[]{});
        for(Class<?> c:cls)ec.addBuiltIn(c);
        return ec;
    }
    /** Returns a mutable Control that bypasses the given Edges */
    public static MutableControl bypass(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*/
    public static MutableControl bypass(String s){ return new EdgeBypass(s); }
    /** Same as bypass(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(Class<?> ... cs){ return new EdgeBypass(cs); }
    
    /** Returns a mutable Control that only traverses the given Edges */
    public static MutableControl only(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 EdgeBypass(pkg,s); }
    /** Returns a mutable Control that traverses only (all) the Edges of the given classes */
    public static MutableControl only(Class<?> ... cs){ return new EdgeOnly(cs); }
    
    /** Returns a mutable Control that ignores the given Edges */
    public static MutableControl remove(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(Class<?> ... cs){ return new EdgeRemove(cs); }
    
    
    
    /** Returns an immutable Control that uses the given strategy */
    //public static Control create(String strtgy){ return new TGControl(strtgy); }
    /** Returns an immutable Control that uses the given ClassGraph and strategy */
    //public static Control create(edu.neu.ccs.demeter.dj.ClassGraph cg, String strtgy){  return new TGControl(cg,strtgy); }
    /** Returns an immutable Control that uses the given ClassGraph */
    //public static Control create(edu.neu.ccs.demeter.dj.ClassGraph cg){  return new TGControl(cg); }
    
    /** Returns whether or not to bypass/skip the given Class/Field */
    public abstract boolean skip(Class<?> c, String f);
    /** Returns whether or not to bypass/skip the given Edge */
    public abstract boolean skip(Edge e);
    /** Returns whether or not to bypass/skip the given Class/Field */
    public abstract boolean ignore(Class<?> c, String f);
    /** Returns whether or not to bypass/skip the given Edge */
    public abstract boolean ignore(Edge e);
    
    /** List of Primitive Classes */
    protected HashSet<Class<?>> builtIns = new HashSet<Class<?>>(32);
    { for(Class<?> c:Util.builtIns)builtIns.add(c); }
    
    /** Returns whether or not tthe given Class is a Builtin */
    public boolean isBuiltInOld(Class<?> c){
        System.err.print("ISBUILT: "+c.getName()+" = ");
        while(c != null){
            if(builtIns.contains(c)){
                System.err.println("true");
                return true;
            }
            c = c.getSuperclass();
        }
        System.err.println("false");
        return false;
    }
    /** Returns whether or not tthe given Class is a Builtin */
    public boolean isBuiltIn(Class<?> c){
        for(Class b:builtIns)
            if(b.isAssignableFrom(c))
                return true;
        return false;
    }
}