package jp.sourceforge.glad.io.iteration;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import jp.sourceforge.glad.collection.closure.ClosureSupport;
import jp.sourceforge.glad.collection.exception.CheckedException;
import jp.sourceforge.glad.collection.exception.ReturnException;
import jp.sourceforge.glad.collection.iteration.IterationHandler;
import jp.sourceforge.glad.collection.iteration.IterationHandlerAdapter;
import junit.framework.TestCase;

public class LinesIterationHandlerTest extends TestCase {

    LinesIterationHandler handler;
    Reader reader;

    protected void setUp() throws Exception {
        reader = loadResource("LinesIterationHandlerTest.txt");
        handler = new LinesIterationHandler(reader);
    }

    protected void tearDown() throws Exception {
        handler = null;
        reader = null;
    }

    public void testIterate() throws IOException {
        handler = new LinesIterationHandler(reader, false);
        try {
            assertTrue(reader.ready());
            final List<String> list = new ArrayList<String>();
            handler.iterate(new ClosureSupport<String>() {
                public void execute(String each) {
                    list.add(each);
                }
            });
            assertEquals(3, list.size());
            assertEquals("[a, b, c]", list.toString());
            assertFalse(reader.ready());
        } finally {
            reader.close();
        }
        assertClosed(reader);
    }

    public void testIterateAndClose() {
        final List<String> list = new ArrayList<String>();
        handler.iterate(new ClosureSupport<String>() {
            public void execute(String each) {
                list.add(each);
            }
        });
        assertEquals(3, list.size());
        assertEquals("[a, b, c]", list.toString());
        assertClosed(reader);
    }

    public void testContinue() {
        final List<String> list = new ArrayList<String>();
        handler.iterate(new ClosureSupport<String>() {
            public void execute(String each) {
                if ("b".equals(each)) {
                    doContinue();
                }
                list.add(each);
            }
        });
        assertEquals(2, list.size());
        assertEquals("[a, c]", list.toString());
        assertClosed(reader);
    }

    public void testBreak() {
        final List<String> list = new ArrayList<String>();
        handler.iterate(new ClosureSupport<String>() {
            public void execute(String each) {
                if ("b".equals(each)) {
                    doBreak();
                }
                list.add(each);
            }
        });
        assertEquals(1, list.size());
        assertEquals("[a]", list.toString());
        assertClosed(reader);
    }

    public void testReturn() {
        final List<String> list = new ArrayList<String>();
        try {
            handler.iterate(new ClosureSupport<String>() {
                public void execute(String each) {
                    if ("b".equals(each)) {
                        doReturn(-1);
                    }
                    list.add(each);
                }
            });
            fail();
        } catch (ReturnException e) {
            assertEquals(-1, e.getResult());
        }
        assertEquals(1, list.size());
        assertEquals("[a]", list.toString());
        assertClosed(reader);
    }

    public void testRuntimeException() {
        final List<String> list = new ArrayList<String>();
        try {
            handler.iterate(new ClosureSupport<String>() {
                public void execute(String each) {
                    if ("b".equals(each)) {
                        throw new RuntimeException("test");
                    }
                    list.add(each);
                }
            });
            fail();
        } catch (RuntimeException e) {
            assertEquals("test", e.getMessage());
        }
        assertEquals(1, list.size());
        assertEquals("[a]", list.toString());
        assertClosed(reader);
    }

    public void testCheckedException() {
        final List<String> list = new ArrayList<String>();
        try {
            handler.iterate(new ClosureSupport<String>() {
                public void execute(String each) throws Exception {
                    if ("b".equals(each)) {
                        throw new Exception("test");
                    }
                    list.add(each);
                }
            });
            fail();
        } catch (CheckedException e) {
            assertEquals("test", e.getCause().getMessage());
        }
        assertEquals(1, list.size());
        assertEquals("[a]", list.toString());
        assertClosed(reader);
    }

    public void testConvert() {
        IterationHandler<Data> handler =
                new IterationHandlerAdapter<String, Data>(
                        new LinesIterationHandler(reader)) {
            @Override
            protected Data convert(String line) {
                return new Data(line);
            }
        };
        final List<Data> list = new ArrayList<Data>();
        handler.iterate(new ClosureSupport<Data>() {
            public void execute(Data each) {
                list.add(each);
            }
        });
        assertEquals(3, list.size());
        assertEquals("[Data(a), Data(b), Data(c)]", list.toString());
        assertClosed(reader);
    }

    Reader loadResource(String name) {
        InputStream is = getClass().getResourceAsStream(name);
        return new InputStreamReader(is);
    }

    void assertClosed(Reader reader) {
        try {
            reader.ready();
            fail();
        } catch (IOException e) {}
    }

    static class Data {
        String value;
        public Data(String value) {
            this.value = value;
        }
        public String getValue() {
            return value;
        }
        public String toString() {
            return "Data(" + value + ")";
        }
    }

}
