import edu.neu.ccs.demeterf.*;
import java.text.DecimalFormat;

// ** Main.java :: BST Test :: Bryan Chadwick
// ** Generates TeX Pictures for BSTs using a few
//      DemeterF transformations

abstract class Comp<T>{ abstract boolean comp(T a, T b); }

class LTE extends Comp<Integer>{
    boolean comp(Integer a, Integer b){ return a<=b; }
}

// 
class BST<T>{
    BST<T> insert(T d, Comp<T> c){ return new Node<T>(d, this, this); }

    // The rest is just for Fun...
    boolean isLeaf(){ return true; }    
    String toTeX(double l, double r, double y){ return ""; }
    static double Y = -3.7;
    
    String toTeX(int w, int h, String title){
        return ("\\setlength{\\unitlength}{0.08in}\n"+
                "\\begin{minipage}[h]{5.5cm}\n"+
                "\\centering{\\large "+title+"}"+
                "\\ \\\\\\ \\\\\\ \\\\\n"+
                "\\begin{picture}("+w+","+h+")"+
                "\n\\setlength{\\unitlength}{0.08in}\n"+
                toTeX(0, w, h)+
                "\\end{picture}\n\\ \\\\\\end{minipage}");
    }
    public String toString()
    { return new Traversal(new ToStr()).traverse(this); }
}
class Node<T> extends BST<T>{
    T data;
    BST<T> left, right;

    Node(T d, BST<T> l, BST<T> r){ data = d; left = l; right = r; }
    BST<T> insert(T d, Comp<T> c){
        if(c.comp(d, data))
            return new Node<T>(data, left.insert(d,c), right);
        return new Node<T>(data, left, right.insert(d,c));
    }

    // The rest is just for Fun...
    static DecimalFormat f = new DecimalFormat("0.0");
    boolean isLeaf(){ return false; }
    String d(double a){ return f.format(a); }
    String toTeX(double l, double r, double y){
        double a = (l+r)/2.0, al = (l+a)/2.0,
               ar = (a+r)/2.0, ny = y+Y;
        int w = Math.max(2, (""+data).length());
        
        return ("\\put("+d(a-w/2.0)+", "+d(y)+
                "){\\framebox("+w+",2){"+data+"}}\n"+
                (left.isLeaf()?"":"\\drawline("+d(a)+
                 ","+d(y)+")("+d(al)+","+d(ny+2)+")\n")+
                (right.isLeaf()?"":"\\drawline("+d(a)+
                 ","+d(y)+")("+d(ar)+","+d(ny+2)+")\n")+
                left.toTeX(l,a,ny)+right.toTeX(a,r,ny));
    }
}

public class Main{
    static LTE cmp = new LTE();
    static BST<Integer> build(int k, BST<Integer> t, int a[]){
        if(k >= a.length)return t;
        return build(k+1, t.insert(a[k], cmp), a);
    }
    static void p(String s){ System.out.print(s); }
    static public void main(String args[]){
        BST<Integer> tree = build(0, new BST<Integer>(),
                                  new int[]{6,3,1,5,0,9,4,7,10,8});
        try{
            int w = Integer.parseInt(args[0]),
                h = Integer.parseInt(args[1]);

            p("\\begin{center}{\n");
            p(tree.toTeX(w,h,"Original"));
            p("}\n\\ \\\\\\ \\\\\\ \\\\\n\n");
            p("\\hbox{");
            // p(new Traversal(new Incr()).traverse(tree).toTeX(w,h,"Incr"));
            p(new Traversal(new Incr()).<BST>traverse(tree).toTeX(w,h,"Incr"));

            p(new Traversal(new Strs()).<BST>traverse(tree).toTeX(w,h,"Strs"));
            p(new Traversal(new Rev()).<BST>traverse(tree).toTeX(w,h,"Rev"));
            p("}\n\\end{center}\n");
        }catch(RuntimeException e){
            p("  Tree: "+tree+"\n");
            p("   Sum: "+new Traversal(new Sum()).traverse(tree)+"\n");
            p("  Incr: "+new Traversal(new Incr()).traverse(tree)+"\n");
            p("Height: "+new Traversal(new Height()).traverse(tree,0)+"\n");
            p("String: "+new Traversal(new Strs()).traverse(tree)+"\n");
        }
    }
}

class ToStr extends IDfb{
    String apply(int i){ return ""+i; }
    String combine(Node t, String d, String l, String r){return "("+d+l+r+")"; }
    String combine(BST l){ return ""; }
}

class Incr extends IDf{ int apply(int i){ return i+1; } }

class Strs extends IDf{
    static String nums[] = {"zero","one","two","three","four","five",
                            "six","seven","eight","nine","ten"};
    String apply(int i){ return nums[i]; }
}

class Rev extends IDb{
    BST combine(Node t, Object d, BST l, BST r){ return new Node(d, r, l); }
    BST combine(BST l){ return l; }
}

class Sum extends IDb{
    int combine(Node t, int d, int l, int r){ return d+r+l; }
    int combine(BST l){ return 0; }
}

class Height extends IDba{
    int update(Node n, int i){ return i+1; }
    int combine(Node t, int d, int l, int r){ return Math.max(l,r); }
    int combine(BST l, int h){ return h; }
}