import java.io.*;
import java.lang.reflect.*;

import edu.rice.cs.mint.runtime.*;
import edu.rice.cs.mint.util.Benchmark;

public class FieldIter {
    public static interface FieldFun {
        public separable <T> Code<Void> call(Code<T> c, ClassCode<T> t);
    }
    
    public static separable <A,B>
        Code<Void> makeCall(FieldFun fun,
                            FieldCode<A,B> fc,
                            final Code<A> obj) {
        return <| { `(fun.call(fc.get(obj), fc.getFieldClassCode())); } |>;
    }
    
    public static <A> Code<Void> fieldIter(FieldFun fun,
                                           Code<A> o,
                                           ClassCode<A> clazz) {
        Code<Void> c = <| { } |>;
        for (final FieldCode<A,?> fc: clazz.getFields())
            c = <| { `c; `(makeCall(fun, fc, o)); } |>;
        return c;
    }
    
    public static class PrintFieldFun implements FieldFun {
        public separable <T> Code<Void> call(Code<T> c, ClassCode<T> t) {
            return <| { System.out.println(`c); } |>;
        }
    }
    
    public static void main(String[] args) throws IOException {
        final Dummy2 d2 = new Dummy2();
        d2.x = 3;
        d2.y = 4;
        
        Code<Void> cd2 = fieldIter(new PrintFieldFun(),
                                   <| d2 |>,
                                   new ClassCode<Dummy2>(Dummy2.class));
        cd2.run();
        
        final Dummy3 d3 = new Dummy3();
        d3.z = 5;
        d3.d2 = d2;
        
        Code<Void> cd3 = fieldIter(new PrintFieldFun(),
                                   <| d3 |>,
                                   new ClassCode<Dummy3>(Dummy3.class));
        cd3.run();
    }
    
    public static final class Dummy2 {
        public int x;
        public int y;
    }
    public static final class Dummy3 {
        public int z;
        public Dummy2 d2;
    }
}
