package terminal;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static terminal.ControlSequenceHandler.isEscape;
import static terminal.SelectGraphicRendition.GREEN;
import static terminal.SelectGraphicRendition.PURPLE;
import static terminal.SelectGraphicRendition.RED;
import static terminal.SelectGraphicRendition.RESET;
import static terminal.SelectGraphicRendition.YELLOW;

import org.junit.Before;
import org.junit.Test;

import stream.SafeInputStream;
import terminal.ControlSequence.NullControlSequence;
import testutil.TestUtilities;
import util.Characters;

public class ControlSequenceHandlerTest {

    private ControlSequenceHandler handler;

    private Object readRemaining(SafeInputStream input) {
        String remaining = "";

        for (int c = input.read(); c != Characters.EOF; c = input.read())
            remaining += (char) c;

        return remaining;
    }

    private SafeInputStream createSafeInputStream(String data) {
        return new SafeInputStream(TestUtilities.createInputStreamFromString(data));
    }

    @Before
    public void setUp() {
        handler = new ControlSequenceHandler();
    }

    @Test
    public void isEscapeDetectsNonEscapeCharacter() {
        assertFalse(isEscape('x'));
    }

    @Test
    public void isEscapeDetectsEscapeCharacter() {
        assertTrue(isEscape('\u001b'));
    }

    @Test
    public void correctlyParsesControlSequence_LeavesRestOfStreamIntact() {
        SafeInputStream input = createSafeInputStream("[32mdata");
        handler.parse(input);
        assertEquals("data", readRemaining(input));
    }

    @Test
    public void unterminatedControlSequence_OnlyConsumesFirstNonSequenceCharacter() {
        SafeInputStream input = createSafeInputStream("[32data");
        handler.parse(input);
        assertEquals("ata", readRemaining(input));
    }

    @Test
    public void malformedControlSequence_OnlyConsumesOneCharacter() {
        SafeInputStream input = createSafeInputStream("32mdata");
        handler.parse(input);
        assertEquals("2mdata", readRemaining(input));
    }

    @Test
    public void parsedControlSequenceIsCorrectType_EOF() {
        SafeInputStream input = createSafeInputStream("");
        assertTrue(handler.parse(input) instanceof NullControlSequence);
    }

    @Test
    public void parsedControlSequenceIsCorrectType_EOF_AfterFirstCharacter() {
        SafeInputStream input = createSafeInputStream("[");
        assertTrue(handler.parse(input) instanceof NullControlSequence);
    }

    @Test
    public void parsedControlSequenceIsCorrectType_UnterminatedControlSequence() {
        SafeInputStream input = createSafeInputStream("[data");
        assertTrue(handler.parse(input) instanceof NullControlSequence);
    }

    @Test
    public void parsedControlSequenceIsCorrectType_MalformedControlSequence() {
        SafeInputStream input = createSafeInputStream("32mdata");
        assertTrue(handler.parse(input) instanceof NullControlSequence);
    }

    @Test
    public void parsedControlSequenceIsCorrectType_SGR_Reset() {
        SafeInputStream input = createSafeInputStream("[0m");
        assertEquals(RESET, handler.parse(input));
    }

    @Test
    public void parsedControlSequenceIsCorrectType_SGR_Red() {
        SafeInputStream input = createSafeInputStream("[31m");
        assertEquals(RED, handler.parse(input));
    }

    @Test
    public void parsedControlSequenceIsCorrectType_SGR_Green() {
        SafeInputStream input = createSafeInputStream("[32m");
        assertEquals(GREEN, handler.parse(input));
    }

    @Test
    public void parsedControlSequenceIsCorrectType_SGR_Yellow() {
        SafeInputStream input = createSafeInputStream("[33m");
        assertEquals(YELLOW, handler.parse(input));
    }

    @Test
    public void parsedControlSequenceIsCorrectType_SGR_Purple() {
        SafeInputStream input = createSafeInputStream("[35m");
        assertEquals(PURPLE, handler.parse(input));
    }

    @Test
    public void parseMultipleControlSequences() {
        SafeInputStream input = createSafeInputStream("[35m[32m[0m");
        assertEquals(PURPLE, handler.parse(input));
        assertEquals(GREEN, handler.parse(input));
        assertEquals(RESET, handler.parse(input));
    }

}
