package org.gnu.grub.fonttool;

import org.junit.Assert;
import org.junit.Test;

public class TestGlyph {
    @Test
    public void testConstructor3x5() {
        Glyph g = new Glyph(65, 3, 5, 0, 0, 0);

        // Should be empty upon construction.
        assertBitmapEquals("..." +
                           "..." +
                           "..." +
                           "..." +
                           "...",
                           g.getBitmap());

        // Should have ceil(3 * 5 / 8) = ceil(15 / 8) = ceil(1 + 7/8) = 2 bytes.
        Assert.assertEquals("Wrong bitmap array size.",
                            2, g.getBitmap().length);
    }

    @Test
    public void testConstructor5x5() {
        Glyph g = new Glyph(65, 5, 5, 0, 0, 0);

        // Should be empty upon construction.
        assertBitmapEquals("....." +
                           "....." +
                           "....." +
                           "....." +
                           ".....",
                           g.getBitmap());

        // Should have ceil(5 * 5 / 8) = ceil(25 / 8) = ceil(3 + 1/8) = 4 bytes.
        Assert.assertEquals("Wrong bitmap array size.",
                            4, g.getBitmap().length);
    }

    @Test
    public void testSetPixel() {
        Glyph g = new Glyph(65, 3, 5, 0, 0, 0);

        g.setPixel(0, 0, true);
        Assert.assertEquals(0x80, g.getBitmap()[0] & 0xFF);
        Assert.assertEquals(0x00, g.getBitmap()[1] & 0xFF);
        assertBitmapEquals("X.." +
                           "..." +
                           "..." +
                           "..." +
                           "...",
                           g.getBitmap());

        g.setPixel(2, 1, true);
        Assert.assertEquals(0x84, g.getBitmap()[0] & 0xFF);
        Assert.assertEquals(0x00, g.getBitmap()[1] & 0xFF);
        assertBitmapEquals("X.." +
                           "..X" +
                           "..." +
                           "..." +
                           "...",
                           g.getBitmap());
    }

    static void assertBitmapEquals(String expectedBitmap, byte[] actualBitmap) {
        Assert.assertNotNull("expected bitmap null", expectedBitmap);
        Assert.assertNotNull("actual bitmap null", actualBitmap);
        StringBuilder errors = new StringBuilder();

        int bit = 7;
        int byteIndex = -1;
        for (int bitIndex = 0; bitIndex < expectedBitmap.length(); bitIndex++) {
            char c = expectedBitmap.charAt(bitIndex);
            boolean expectedBit;
            if (c == '.') {
                expectedBit = false;
            } else if (c == 'X') {
                expectedBit = true;
            } else {
                throw new IllegalArgumentException("Bad character '" + c + "' in expected bitmap string");
            }

            byteIndex = bitIndex / 8;
            byte b = actualBitmap[byteIndex];
            boolean actualBit = (b & (1 << bit)) != 0;
            if (actualBit != expectedBit) {
                errors.append("[").append(bitIndex)
                        .append("] wrong (it is ")
                        .append(actualBit ? "1" : "0").append("). ");
            }

            if (bit == 0) {
                bit = 7;
            } else {
                bit--;
            }
        }

        if (byteIndex != expectedBitmap.length() / 8) {
            errors.append("Last byte index wrong, was ")
                    .append(byteIndex).append(" but expected ")
                    .append(expectedBitmap.length() - 1);
        }

        if (errors.length() != 0) {
            Assert.fail("Bitmap wrong: " + errors);
        }
    }
}
