/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.text.format;

import java.io.IOException;
import java.util.List;
import net.ranides.assira.collection.ListUtils;
import net.ranides.assira.collection.list.VirtualList;
import net.ranides.assira.generic.Serializer;
import net.ranides.assira.text.format.AnsiRegion;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author ranides
 */
@SuppressWarnings("PMD")
public class AnsiStringTest {
    
    @Test
    public void testCopy() {
        AnsiString input = new AnsiString("(hello world!)");
        
        AnsiString c1 = new AnsiString(input);
        
        assertEquals(c1, input);
        
        input.setCharAt(0, '[');
        input.setCharAt(input.length()-1, ']');
        c1.setCharAt(0, '<');
        c1.setCharAt(input.length()-1, '>');
        
        assertFalse(input.equals(c1));
        assertEquals("[hello world!]", input.toString());
        assertEquals("<hello world!>", c1.toString());
        
        AnsiString c2 = new AnsiString(input, 1, input.length()-1);
        
        c2.setCharAt(0, 'H');
        c2.setCharAt(c2.length()-1, '?');
        assertEquals("[hello world!]", input.toString());
        assertEquals("<hello world!>", c1.toString());
        assertEquals("Hello world?", c2.toString());
        
        AnsiCharSequence s1 = input.subSequence(1, input.length()-2);
        AnsiString c3 = new AnsiString(s1, 3, s1.length()-1);
        assertEquals("lo worl", c3.toString());
    }
    
    @Test
    public void testCapacity() {
        AnsiString text = new AnsiString(4);
        text.setCharAt(0, 'h');
        text.setCharAt(1, 'o');
        text.setCharAt(2, 'm');
        text.setCharAt(3, 'e');
        text.setFore(0, 4, 33);
        text.setBack(0, 4, 17);
        
        assertEquals("home", text.toString());
        assertEquals(4, text.length());
    }
    
    @Test
    public void testCompare() {
        AnsiString v1 = new AnsiString("home");
        v1.setFore(0, 4, 33);
        v1.setBack(0, 4, 17);
        
        assertEquals("home", v1.toString());
        
        AnsiString v2 = new AnsiString("home");
        assertTrue( v1.equals(v2, AnsiAttr.CMP_CHAR) );
        assertFalse( v1.equals(v2, AnsiAttr.CMP_PUBLIC) );
        
        AnsiString v3 = new AnsiString("data");
        v3.setFore(0, 4, 33);
        v3.setBack(0, 4, 17);
        v3.setFlags(0, 4, AnsiAttr.FRESH);
        
        assertFalse( v1.equals(v3, AnsiAttr.CMP_CHAR) );
        assertTrue( v1.equals(v3, AnsiAttr.CMP_FORE | AnsiAttr.CMP_BACK) );
        assertTrue( v1.equals(v3, AnsiAttr.CMP_FLAGS_PUBLIC) );
        assertFalse( v1.equals(v3, AnsiAttr.CMP_FLAGS_ALL) );
        
        AnsiCharSequence v4 = v3.subSequence(0, 4);
        assertFalse( v1.equals(v4, AnsiAttr.CMP_CHAR) );
        assertTrue( v1.equals(v4, AnsiAttr.CMP_FORE | AnsiAttr.CMP_BACK) );
        assertTrue( v1.equals(v4, AnsiAttr.CMP_FLAGS_PUBLIC) );
        assertFalse( v1.equals(v4, AnsiAttr.CMP_FLAGS_ALL) );
        
        AnsiCharSequence v5 = new AnsiString("homes");
        assertFalse(v1.equals(v5));
        
        AnsiCharSequence v6 = new AnsiString("home");
        AnsiCharSequence v7 = new AnsiString("home");
        v6.setFont(0, 1, 19);
        v6.setFont(2, 4, 21);
        v7.setFont(0, 1, 17);
        v7.setFont(2, 4, 21);
        
        assertTrue( v6.equals(v7, AnsiAttr.CMP_CHAR));
        assertFalse( v6.equals(v7, AnsiAttr.CMP_FONT));
        
        assertFalse( v6.equals(v7) );
        assertTrue( v6.subSequence(2, 4).equals(v7.subSequence(2, 4)));
    }
    
    @Test
    public void testFlags() {
        AnsiString text = new AnsiString("Hello world!");
        text.setFlags(0, 5, AnsiAttr.BOLD);
        text.setFlags(2, 12, AnsiAttr.NARROW);
        text.setFlags(8, 12, AnsiAttr.UNDERLINE | AnsiAttr.NO_NARROW);
        
        assertEquals(AnsiAttr.BOLD, text.getFlagsAt(1));
        assertEquals(AnsiAttr.BOLD | AnsiAttr.NARROW, text.getFlagsAt(3));
        assertEquals(AnsiAttr.NARROW, text.getFlagsAt(6));
        assertEquals(AnsiAttr.UNDERLINE, text.getFlagsAt(9));
    }

    @Test
    public void testSubsequence() {
        AnsiString text = new AnsiString("(hello world!)");
        
        AnsiCharSequence a = text.subSequence(1, text.length()-1);
        
        AnsiCharSequence b = a.subSequence(6, a.length()-1);
        
        AnsiCharSequence c = text.subSequence(6, text.length()-1);
                
        assertEquals("hello world!", a.toString());
        
        assertEquals("world", b.toString());
        
        assertEquals(" world!", c.toString());
        
        text.setCharAt(1, 'H');
        
        text.setCharAt(7, 'W');
        
        text.setCharAt(12, '?');
        
        assertEquals("Hello World?", a.toString());
        
        assertEquals("World", b.toString());
        
        assertEquals(" World?", c.toString());
        
        a.setAttr(1, 4, AnsiStrings.attr("3 4 +b"));
        a.replace(1, "ouse");
        
        assertEquals("(House World?)", text.toString());
        
        AnsiString exp = new AnsiString("(House World?)");
        exp.setAttr(2, 5, AnsiStrings.attr("3 4 +b"));
        
        assertEquals(exp, text);
        
        assertTrue( a.equals(a) );
        assertTrue( text.subSequence(1, 5).equals(text.subSequence(1, 5)) );
        assertFalse( text.subSequence(1, 5).equals(text.subSequence(1, 6)) );
        assertFalse( text.subSequence(1, 5).equals(text) );
    }
    
    @Test
    public void testSerialization() throws IOException {
        AnsiCharSequence sequence = AnsiGenerator.make("Hello world!");
        AnsiCharSequence input = sequence.subSequence(3, 7);
        
        AnsiCharSequence output = Serializer.copy(input);
        
        assertEquals(input, output);
    }
    
    @Test
    public void testSerialization2() throws IOException {
        final AnsiCharSequence sequence = AnsiGenerator.make("Hello world!");
        final AnsiAttr input = sequence.getAttrAt(3);
        
        AnsiAttr output = Serializer.copy(input);
        
        assertEquals(input, output);
        
        Serializer.SizeInfo sizeinfo = Serializer.sizeof(new VirtualList<AnsiAttr>() {
            @Override
            public int size() { return 100; }
            @Override
            public AnsiAttr get(int index) { return sequence.getAttrAt(index%sequence.length()); }
        });
        assertEquals(15, sizeinfo.self());
        assertEquals(812, sizeinfo.attached());
    }
    
    @Test
    public void testAtFunctions() {
        AnsiCharSequence text = new AnsiString("Hello world!");
        text.setAttrAt(2, AnsiStrings.attr(3, 17, 8, AnsiAttr.BOLD));
        
        text.setAttrAt(3, AnsiStrings.attr(3, 17, 8, AnsiAttr.NARROW));
        text.setAttrAt(3, AnsiStrings.attr(4, 18, 9));
        
        assertEquals(AnsiStrings.attr(3, 17, 8, AnsiAttr.BOLD), text.getAttrAt(2));
        assertEquals(AnsiStrings.attr(4, 18, 9), text.getAttrAt(3));
        
        AnsiAttr a1 = AnsiStrings.attr(3, 17, 8, AnsiAttr.MASK_FLAGS_CLR | AnsiAttr.BOLD);
        AnsiAttr a2 = AnsiStrings.attr(3, 17, 8, AnsiAttr.BOLD);
        
        
        assertTrue(a1.equals(a2));
        assertTrue(a1.equals(a2, AnsiAttr.CMP_FLAGS_ALL));
        assertFalse(a1.equals(a2, AnsiAttr.CMP_IDENTICAL));
        
        text.setBackAt(5, 31);
        text.setForeAt(5, 32);
        text.setFontAt(5, 33);
        text.setFlagsAt(5, AnsiAttr.BOLD | AnsiAttr.NO_NARROW);

        assertFalse(AnsiStrings.attr("31 32 33 +b-n").equals(a2, AnsiAttr.CMP_ALL));
    }
    
    @Test
    public void testRegions() {
        AnsiCharSequence text = new AnsiString("(Hello world!)");
        
        List<AnsiRegion> r1 = ListUtils.asList(text.regions(AnsiAttr.CMP_ALL));
        assertEquals(1, r1.size());
        assertEquals(AnsiStrings.attr(0,0,0), r1.get(0).attr());
        assertEquals("(Hello world!)", r1.get(0).value().toString());

        text.setAttr(1, 3, AnsiStrings.attr("4 17"));
        text.setFont(2, 9, 8);
        text.setFlags(7, 12, AnsiAttr.BOLD);

        List<AnsiRegion> r2 = ListUtils.asList(text.regions(AnsiAttr.CMP_ALL));
        assertEquals(7, r2.size());
        assertEquals("(",    r2.get(0).value().toString());
        assertEquals("H",    r2.get(1).value().toString());
        assertEquals("e",    r2.get(2).value().toString());
        assertEquals("llo ", r2.get(3).value().toString());
        assertEquals("wo",   r2.get(4).value().toString());
        assertEquals("rld",  r2.get(5).value().toString());
        assertEquals("!)",   r2.get(6).value().toString());
    }
    
    @Test
    public void testSignConversion() {
        AnsiCharSequence text =new AnsiString("Text");
        text.setForeAt(0, 220);
        text.setForeAt(1, 128);
        text.setBackAt(0, 220);
        text.setBackAt(1, 128);
        text.setFontAt(0, 220);
        text.setFontAt(1, 128);
        
        assertEquals(220, text.getForeAt(0));
        assertEquals(128, text.getForeAt(1));
        assertEquals(220, text.getBackAt(0));
        assertEquals(128, text.getBackAt(1));
        assertEquals(220, text.getFontAt(0));
        assertEquals(128, text.getFontAt(1));
    }
}
