package util;

import junit.framework.TestCase;

import com.fasterxml.aalto.in.*;

public class TestPNameTable
    extends TestCase
{
    final static String UTF8 = "UTF-8";

    public void testUTF8()
    {
        ByteBasedPNameTable table = new ByteBasedPNameTable(16);
        final String[] names = new String[] {
            "someElementName", "a", "ns:a", "a:ns",
            "foobar", "_x11:elem", "attribute", "x",
            "xml:id", "Soap:Envelope", "root", "branch",
            "SomeSlightlyLongerNsPrefix:andElementNameToo", "b", "ab", "aaaa"
        };
        for (int i = 0; i < names.length; ++i) {
            String currWord = names[i];

            // Shouldn't be found yet:
            assertNull(tryToFind(table, currWord));
            assertEquals(i, table.size());

            // So let's add it
            PName added = addSymbol(table, currWord);
            assertNotNull(added);

            // Should now find it
            assertEquals(added, tryToFind(table, currWord));
            assertEquals(i+1, table.size());

            // ... as well as all prior words:
            for (int j = i; --j >= 0; ) {
                PName other = tryToFind(table, names[j]);
                if (other == null) {
//System.err.println("FAIL: table('"+names[j]+"') == "+table.toDebugString());
                    fail("Should have found '"+names[j]+"' (entry #"+j+" out of "+i+")");
                }
                assertEquals(names[j], other.getPrefixedName());
            }
        }
    }

    /*
    /**********************************************************************
    /* Internal methods
    /**********************************************************************
     */

    PName tryToFind(ByteBasedPNameTable table, String word)
    {
        int[] quads = calcQuads(word);
        int hash = ByteBasedPNameTable.calcHash(quads, quads.length);
        if (quads.length < 3) {
            return table.findSymbol(hash, quads[0], (quads.length < 2) ? 0 : quads[1]);
        }
        return table.findSymbol(hash, quads, quads.length);
    }

    PName addSymbol(ByteBasedPNameTable table, String word)
    {
        int[] quads = calcQuads(word);
        int colonIx = word.indexOf(':');
        int hash = ByteBasedPNameTable.calcHash(quads, quads.length);
        if (quads.length < 3) {
            return table.addSymbol(hash, word, colonIx, quads[0], (quads.length < 2) ? 0 : quads[1]);
        }
        return table.addSymbol(hash, word, colonIx, quads, quads.length);
    }

    int[] calcQuads(String word)
    {
        byte[] wordBytes;
        try {
            wordBytes = word.getBytes(UTF8);
        } catch (java.io.UnsupportedEncodingException ex) {
            throw new Error("Internal error: "+ex); // should never occur
        }
        int blen = wordBytes.length;
        int[] result = new int[(blen + 3) / 4];
        for (int i = 0; i < blen; ++i) {
            int x = wordBytes[i] & 0xFF;

            if (++i < blen) {
                x = (x << 8) | (wordBytes[i] & 0xFF);
                if (++i < blen) {
                    x = (x << 8) | (wordBytes[i] & 0xFF);
                    if (++i < blen) {
                        x = (x << 8) | (wordBytes[i] & 0xFF);
                    }
                }
            }
            result[i / 4] = x;
        }

        return result;
    }
}
