package edu.neu.ccs.demeterf.examples;
import edu.neu.ccs.demeterf.control.Fields;
import edu.neu.ccs.demeterf.*;

/** Example of the new Augmentor (update) protocol. Classes with fields contain
 *    inner (public) classes that share the field names. DemeterF will try to create
 *    an instance of this inner field class and find an update method with an
 *    applicable signature, before traversing that field.
 *    <p> Here we show Huffman tree paths, encoded as the string from root to each
 *    leaf.  On the way down the tree, we add the next path portion to the traversal
 *    argument (String).  At the leafs we return a list of the data/path as a string.    
 *    </p> */
public class NewUpdate{
    public static void main(String s[]){
        huff tree = huff.make(4, 2, 5, 1, 3, 6, 8, 6); 
        
        System.out.println(" Tree: "+new Traversal(new ID(){
            String combine(node n, String l, String r){ return "("+l+","+r+")"; }
            String combine(leaf l, int i){ return ""+i; }        
        }).traverse(tree)+"\n");
        
        System.out.println(" Paths:\n"+new Traversal(new T()).traverse(tree,"root")+"\n");
    }

    // Collects the paths to all leafs with data into a list-of Strings 
    static class T extends ID{
        String update(node n, node.left f, String s){ return s+".left"; }
        String update(node n, node.right f, String s){ return s+".right"; }
        L combine(node n, L l, L r){ return l.append(r); }
        L combine(leaf l, int i, String p){ return new L().push("["+i+" : "+p+"]"); }
    }
    
    // Abstract Huffman tree with static methods
    static abstract class huff{    
        static huff make(int ... xs){
            huff ts[] = new huff[xs.length];
            for(int i = 0; i < xs.length; i++)
                ts[i] = new leaf(xs[i]);
            return make(ts,1);
        }
        static huff make(huff ts[], int skip){
            if(skip >= ts.length)return ts[0];
            for(int i = 0; i < ts.length; i += skip*2)
                ts[i] = new node(ts[i],ts[i+skip]);
            return make(ts,skip*2);
        }
    }
    // Node, with left/right... no data
    public static class node extends huff{
        huff left, right;
        node(huff l, huff r){ left = l; right = r; }
        public static class left extends Fields.any{}
        public static class right extends Fields.any{}
    }
    // Leaf, contains an integer
    public static class leaf extends huff{
        int data;
        leaf(int d){ data = d; }
        public static class data extends Fields.any{}
    }
    
    // Simple list-of-strings classes
    static class L{ 
        L push(String s){ return new CL(s,this); }
        L append(L l){ return l; }
        public String toString(){ return ""; }
    }
    static class CL extends L{
        String first; L rest;
        CL(String f, L r){ first = f; rest = r; }
        L append(L l){ return rest.append(l).push(first); }
        public String toString(){ return "    "+first+",\n"+rest; }
    }
}