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

/** Container Checking using the Transform Library
 *    Uses a type-unifying traversal to produce the violations
 *    and total weight of each Container (C) 
 */

// Main Test Class
public class ContainerTest{
    public static void main(String args[]){
        I i = new C(10, List.from(new E(5),
                 new C(8, List.from(
                    new C(6, List.from(new E(2),new E(4))),
                    new E(3)))));
            
        Pair p = new Traversal(new Check()).traverse(i);
        System.out.println("       Item = "+i);
        System.out.println("     Weight = "+p.w);
        System.out.println(" Violations = "+p.v);
    }
    
    // Items
    static abstract class I{
        public String toString(){ return new Traversal(new ID(){
            String combine(C ct, int c, String is){ return "C["+c+", "+is+"]"; }
            String combine(E e, int w){ return "E["+w+"]"; }
            String combine(Empty l){ return ""; }
            String combine(Cons c, String f, String r){ return "("+f+r+")"; }
        }).traverse(this); }
    }
    // Containers
    static class C extends I{
        int cap; List items;
        C(int c, List i){ cap = c; items = i; }
    }
    // Elements
    static class E extends I{
        int weight;
        E(int w){ weight = w; }
    }

    // ItemLists
    static abstract class List{
        static List from(I ... items){
            List list = new Empty();
            for(I i:items)list = new Cons(i,list);
            return list;
        }
    }
    // Cons ItemList
    static class Cons extends List{
        I first;
        List rest;
        Cons(I f, List r){ first = f; rest = r; }
    }
    // Empty ItemList
    static class Empty extends List{}

    // Pair of ints, <weight, violations>
    static class Pair{
        int w,v;
        Pair(int ww, int vv){ w = ww; v = vv; }
        static Pair make(int ww, int vv){ return new Pair(ww,vv); }
        Pair add(int ww, int vv){ return make(w+ww,v+vv); }
        Pair add(Pair p){ return make(w+p.w,v+p.v); }
    }

    // Checker, Type-unifying to Pair(int,int)
    static class Check extends ID{
        Pair combine(E e, int i){ return Pair.make(e.weight,0); }
        Pair combine(C c, int i, Pair wv){ return wv.add(0, (wv.w > c.cap)?1:0); }
        Pair combine(Empty l){ return Pair.make(0,0); }
        Pair combine(Cons l, Pair f, Pair r){ return f.add(r); }
    }
}