/*
 * Copyright 2010 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */

package java.lang;

import java.io.DataInputStream;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.zip.InflaterInputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;

/**
 * @author Xueming Shen
 * @author Ulf Zibis, Cologne CoSoCo.de
 * @see    Character
 * @since  1.7
 */
class CharacterName2 {

    private static SoftReference<byte[]> refNames;
    private static int[][] indexes = null; // containes indexes and lengths

    private static synchronized byte[] getNames() throws Exception {
        byte[] names = null;
        DataInputStream dis = null;
        try {
            dis = new DataInputStream(new InflaterInputStream(
                AccessController.doPrivileged(new PrivilegedAction<InputStream>() {
                    public InputStream run() {
                        return getClass().getResourceAsStream("uniName.dat");
                    }
            })));
            // read character names as ASCII bytes
            dis.readFully(names = new byte[dis.readInt()]);
            if (indexes == null) {
                // instatiate index arrays
                indexes = new int[(Character.MAX_CODE_POINT+1)>>8][];
                int[][] indexes = CharacterName2.indexes; // fast local copy
                for (char block=0; block<indexes.length; block++) {
                    byte[] indexesLengths = new byte[indexes[block].length];
                    dis.readFully(indexesLengths);
                    for (byte len : indexesLengths)
                        if (len != 0) // only allocate space for used indexes
                            indexes[block] = new int[len&0xFF];
                }
                // read indexes and lengths for character names bytes in names[]
                for (int len, i=0, cp=0; (len = dis.read()) >= 0; i+=len) {
                    char block;
                    if (len < 0x80) // allows maximum character name length of 127
                        block = (char)(++cp >> 8);
                    else {
                        len &= 0x7F; // allows maximum character name length of 126
                        block = dis.readChar();
                        cp = block << 8 | dis.read() & 0xFF;
                    }
                    indexes[block][cp&0xFF] = (i << 8) | len; // see Bug 6933327
                }
            }
        } finally {
            dis.close();
        }
        return names;
    }

    public static String get(int cp) {
        try {
            byte[] names;
            if (refNames == null || (names = refNames.get()) == null)
                refNames = new SoftReference<>(names = getNames());
            int[] indexBlock = indexes[(char)(cp >> 8)]; // fast local copy
            int index;
            if (indexBlock == null ||
                    indexBlock.length <= (cp & 0xFF) ||
                    (index = indexBlock[cp&0xFF]) == 0)
                return null;
            return new String(names, index >> 8, index & 0xFF, "ASCII");
        } catch (Exception e) {
            InternalError err = new InternalError(e.toString());
            err.initCause(e);
            throw err;
        }
    }
}
