/**********************************************
 *  AOSD 10 Submission Files                  *
 *  MaxEnv.java :                             *
 *    Runs performance tests for the maxenv   *
 *    function                                *
 *                                            *
 *********************************************/

import gen.*;
import edu.neu.ccs.demeterf.lib.*;
import edu.neu.ccs.demeterf.*;
import java.io.FileInputStream;

public class MaxEnv extends StaticTU<Integer>{
    static void p(String s){ System.out.println(s); }
    public static void main(String[] args) throws Exception{
        String names[] = {"Hand","Vis","Inln","Reflect"};
        if(args.length != 2){
            System.err.println("usage: java MaxEnv <file> <which>");
            return;
        }
        Exp ee = Exp.parse(new FileInputStream(args[0]));
        int e = 0;
        int what = Integer.parseInt(args[1]);
        long st = System.currentTimeMillis();
        switch(what){
        case 0:e = new MaxEnv().maxEnvHand(ee);break;
        case 1:e = new MaxEnv().maxEnvVis(ee);break;
        case 2:e = new MaxEnv().maxEnvInln(ee);break;
        case 3:e = new MaxEnv().maxEnvRefl(ee);break;
        }
        p("MaxEnv["+names[what]+"]: "+(System.currentTimeMillis()-st));
        //p("Result: "+e);
    }

    public Integer combine(){ return 0; }
    public Integer fold(Integer a, Integer b)
    { return Math.max(a,b); }
   
    public Integer combine(Def c, int id, int e, int b)
    { return fold(e, 1+b); }

    int maxEnvHand(Exp e)
    { return e.maxEnv(); }
    int maxEnvVis(Exp e)
    { return e.accept(new MaxEnvEVis()); }
    int maxEnvInln(Exp e)
    { return new InlineMaxEnv(this).traverse(e); }
    int maxEnvRefl(Exp e)
    { return new Traversal(this).<Integer>traverse(e); }
}

class MaxEnvEVis extends Exp.Vis<Integer>{
    int max(int a, int b){ return Math.max(a,b); }
    public Integer visit(Bin b){ return max(b.getLeft().accept(this),b.getRight().accept(this)); }
    public Integer visit(Var v){ return 0; }
    public Integer visit(Def d){ return max(d.getE().accept(this),1+d.getBody().accept(this)); }
    public Integer visit(Ifz f){ return max(max(f.getCnd().accept(this),
                                                f.getThn().accept(this)),
                                            f.getEls().accept(this)); }
    public Integer visit(Num n){ return 0; }
}