package edu.neu.ccs.demeterf.examples;
/** Type Unifying Example Class.  */

import edu.neu.ccs.demeterf.TU;
import edu.neu.ccs.demeterf.Control;

// Example Binary Tree Representation...
abstract class BTree{}
class Leaf extends BTree{ 
    int data;
    Leaf(int i){ data = i; }
}
class BNode extends BTree{
   BTree left, right;
   BNode(BTree l, BTree r){ left = l; right = r; }
}

// Actual TU Class
class CountLeafs extends TU<Integer>{
   public Integer combine(){ return 0; }
   public Integer fold(Integer i, Integer j){ return i+j; }
   int combine(Leaf l){ return 1; }
   
   static int leafs(BTree t){
       return new CountLeafs().traverse(t);
   }
} 

// Other classes unchanged...
class BNode2 extends BNode{
   int data;
   BNode2(int d, BTree l, BTree r){ super(l,r); data = d; }
}

// Modified TU Class
class CountLeafs2 extends CountLeafs{
   int combine(BTree t, int d, int l, int r){ return l+r; }
   static int leafs(BTree t){
       return new CountLeafs2().traverse(t);
   }
} 

// Return of the Traversal
class MyInt{
   int i;
   MyInt(int j){ i = j; }
   MyInt plus(MyInt j){ return new MyInt(i+j.i); }
}

// New TU Class
class CountLeafs3 extends TU<MyInt>{
   public MyInt combine(){ return new MyInt(0); }
   public MyInt fold(MyInt i, MyInt j){ return i.plus(j); }
   MyInt combine(Leaf l){ return new MyInt(1); }
   
   static int leafs(BTree t){
       return new CountLeafs3().traverse(t).i;
   }
}

// New TU Control Test Class
class CountLeafs4 extends TU<MyInt>{
   public MyInt combine(){ return new MyInt(0); }
   public MyInt fold(MyInt i, MyInt j){ return i.plus(j); }
   MyInt combine(BNode n, MyInt l, BTree r){ return l; }
   MyInt combine(Leaf l){ return new MyInt(1); }
   
   static int leafs(BTree t){
       return new CountLeafs4().traverse(t,
               Control.bypass("edu.neu.ccs.demeterf.examples.BNode.right")).i;
   }
}

/** TUCombiner Example */
public class TUExample {
    static void p(String s){ System.out.println(s); }
    public static void main(String s[]){
        BTree noDTree = new BNode(new BNode(new Leaf(4), 
                new Leaf(5)), new BNode(new Leaf(6), new Leaf(8)));
        BTree dTree = new BNode2(6, new BNode2(4, new Leaf(3), 
                new Leaf(5)), new BNode2(8, new Leaf(7), new Leaf(9)));
        
        p("                 CountLeafs[4]: "+CountLeafs.leafs(noDTree));
        p("            !Bad CountLeafs[4]: "+CountLeafs.leafs(dTree));
        p("                CountLeafs2[4]: "+CountLeafs2.leafs(dTree));
        p(" w/o  Node Data CountLeafs3[4]: "+CountLeafs3.leafs(noDTree));
        p(" with Node Data CountLeafs3[4]: "+CountLeafs3.leafs(dTree));
        p("           Left CountLeafs4[1]: "+CountLeafs4.leafs(noDTree));
        p("           Left CountLeafs4[4]: "+CountLeafs4.leafs(dTree));
    }
}