import junit.framework.TestCase;

import lrs.*;
import lrs.lazyLRSEvaluators.*;

public class LazyAddEvalTest extends TestCase {
    private static final IAlgo isE = new IAlgo() {
        public Object emptyCase(LRStruct host, Object... inp) {
            return true;
        }
        public Object nonEmptyCase(LRStruct host, Object... inp) {
            return false;
        }
    };
    
    public static void assertEmpty(LRStruct l) {
        assertTrue((Boolean)l.execute(isE));
    }
    public static void assertNonEmpty(LRStruct l) {
        assertFalse((Boolean)l.execute(isE));
    }
    public static void assertFirst(LRStruct l, int i) {
        assertFalse((Boolean)l.execute(isE));
        assertEquals((Integer)i, (Integer)l.getFirst());
    }

    public void testEmptyEmpty() {
        LRStruct a = new LRStruct();
        LRStruct b = new LRStruct();
        LRStruct res = new LazyAddEval(a,b).makeLRS();
        assertEmpty(res);
    }

    public void testEmptyOne() {
        LRStruct a = new LRStruct();
        LRStruct b = new LRStruct();
        b.insertFront(1);
        LRStruct res = new LazyAddEval(a,b).makeLRS();
        assertFirst(res, 1);
        assertEmpty(res.getRest());
    }

    public void testEmptyTwo() {
        LRStruct a = new LRStruct();
        LRStruct b = new LRStruct();
        b.insertFront(2);
        b.insertFront(1);
        LRStruct res = new LazyAddEval(a,b).makeLRS();
        assertFirst(res, 1);
        assertFirst(res.getRest(), 2);
        assertEmpty(res.getRest().getRest());
    }

    public void testEmptyInf() {
        LRStruct a = new LRStruct();
        LRStruct b = new LazyConstantEval(1).makeLRS();
        LRStruct res = new LazyAddEval(a,b).makeLRS();
        for(int i=0; i<1000; ++i) {
            assertFirst(res, 1);
            assertNonEmpty(res.getRest());
            res = res.getRest();
        }
    }
    
    public void testOneEmpty() {
        LRStruct a = new LRStruct();
        LRStruct b = new LRStruct();
        b.insertFront(1);
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        assertFirst(res, 1);
        assertEmpty(res.getRest());
    }

    public void testTwoEmpty() {
        LRStruct a = new LRStruct();
        LRStruct b = new LRStruct();
        b.insertFront(2);
        b.insertFront(1);
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        assertFirst(res, 1);
        assertFirst(res.getRest(), 2);
        assertEmpty(res.getRest().getRest());
    }

    public void testInfEmpty() {
        LRStruct a = new LRStruct();
        LRStruct b = new LazyConstantEval(1).makeLRS();
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        for(int i=0; i<1000; ++i) {
            assertFirst(res, 1);
            assertNonEmpty(res.getRest());
            res = res.getRest();
        }
    }
    
    public void testOneOne() {
        LRStruct a = new LRStruct();
        a.insertFront(10);
        LRStruct b = new LRStruct();
        b.insertFront(1);
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        assertFirst(res, 11);
        assertEmpty(res.getRest());
    }

    public void testTwoOne() {
        LRStruct a = new LRStruct();
        a.insertFront(10);
        LRStruct b = new LRStruct();
        b.insertFront(2);
        b.insertFront(1);
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        assertFirst(res, 11);
        assertFirst(res.getRest(), 2);
        assertEmpty(res.getRest().getRest());
    }

    public void testInfOne() {
        LRStruct a = new LRStruct();
        a.insertFront(10);
        LRStruct b = new LazyConstantEval(1).makeLRS();
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        assertFirst(res, 11);
        assertNonEmpty(res.getRest());
        res = res.getRest();
        for(int i=0; i<1000; ++i) {
            assertFirst(res, 1);
            assertNonEmpty(res.getRest());
            res = res.getRest();
        }
    }
    
    public void testOneTwo() {
        LRStruct a = new LRStruct();
        a.insertFront(20);
        a.insertFront(10);
        LRStruct b = new LRStruct();
        b.insertFront(1);
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        assertFirst(res, 11);
        assertFirst(res.getRest(), 20);
        assertEmpty(res.getRest().getRest());
    }

    public void testTwoTwo() {
        LRStruct a = new LRStruct();
        a.insertFront(20);
        a.insertFront(10);
        LRStruct b = new LRStruct();
        b.insertFront(2);
        b.insertFront(1);
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        assertFirst(res, 11);
        assertFirst(res.getRest(), 22);
        assertEmpty(res.getRest().getRest());
    }

    public void testInfTwo() {
        LRStruct a = new LRStruct();
        a.insertFront(20);
        a.insertFront(10);
        LRStruct b = new LazyConstantEval(1).makeLRS();
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        assertFirst(res, 11);
        assertNonEmpty(res.getRest());
        res = res.getRest();
        assertFirst(res, 21);
        assertNonEmpty(res.getRest());
        res = res.getRest();
        for(int i=0; i<1000; ++i) {
            assertFirst(res, 1);
            assertNonEmpty(res.getRest());
            res = res.getRest();
        }
    }
    
    public void testTwoInf() {
        LRStruct a = new LRStruct();
        a.insertFront(20);
        a.insertFront(10);
        LRStruct b = new LazyConstantEval(1).makeLRS();
        LRStruct res = new LazyAddEval(a,b).makeLRS();
        assertFirst(res, 11);
        assertNonEmpty(res.getRest());
        res = res.getRest();
        assertFirst(res, 21);
        assertNonEmpty(res.getRest());
        res = res.getRest();
        for(int i=0; i<1000; ++i) {
            assertFirst(res, 1);
            assertNonEmpty(res.getRest());
            res = res.getRest();
        }
    }

    public void testInfInf() {
        LRStruct a = new LazyIncEval(0,1).makeLRS();
        LRStruct b = new LazyConstantEval(1).makeLRS();
        LRStruct res = new LazyAddEval(b,a).makeLRS();
        for(int i=0; i<1000; ++i) {
            assertFirst(res, i+1);
            assertNonEmpty(res.getRest());
            res = res.getRest();
        }
    }
}
