/* Traversal.java
 * Bryan Chadwick :: 2007
 * Normal parametrized traversal "function" */

package edu.neu.ccs.demeterf;

import edu.neu.ccs.demeterf.dispatch.MethodDB;
import java.lang.reflect.*;
import edu.neu.ccs.demeterf.util.*;


/** Traverses an Object structure using a Builder and an Augmentor. */
public class Traversal extends AbstTraversal{
    /* Builder and Augmentor */
    protected FC func;
    protected MethodDB<Method> buildDB;
    protected MethodDB<Method> augDB;

    /** Create a onestep Traversal with the given functionality */
    public static Traversal onestep(ID id){ return new Traversal(id,Control.nowhere()); }
    
    /** Create a parameterized Traversal that goes Everywhere */
    public Traversal(FC f){ this(f, Control.everywhere()); }
    /** Create a Traversal with Selective edge/field Bypassing */
    public Traversal(FC f, Control c){
        super(c);
        func = f; 
        buildDB = MethodDB.createMethodDB(f.getClass(),FC.buildMethodName);
        augDB = MethodDB.createMethodDB(f.getClass(), FC.augMethodName);
    }
    
    /** Apply the Builder to this list of 'Fields' */    
    protected Object applyBuilder(Object o[], boolean prim)
    { return Util.applyFObj(func, o, buildDB, FC.buildMethodName, prim?0:-1); }
    
    /** Apply the Augmentor to the Argument at this Object before
     *    traversing the given field. */
    protected Object applyAugment(Object o[], Class<?> pc, String fn){
        Object field = Fields.any;
        if(pc != null){
            // Look for a class that represents the field
            String fName = pc.getName()+"$"+fn;
            try{
                Class<?> fc = Class.forName(fName);
                Constructor<?> con = fc.getConstructor(new Class[0]);
                con.setAccessible(true);
                field = con.newInstance(new Object[0]);
            }catch(ClassNotFoundException e){
                //System.out.println(" Field Class Not Found: "+fName);
            }catch(InstantiationException e){
                System.out.println(" Cannot Instantiate: "+fName);
            }catch(IllegalAccessException e){
            }catch(NoSuchMethodException e){
            }catch(InvocationTargetException e){ throw new RuntimeException(e); }
        }
        return Util.applyFObj(func, new Object[]{o[0],field,o[1]},augDB, FC.augMethodName, 2);
    }
}