// Copyright 2001, FreeHEP.

package com.cherry.lib.doc.office.thirdpart.emf.font;

import java.io.IOException;

/**
 * CMAP Table.
 * 
 * @author Simon Fischer
 * @version $Id: TTFCMapTable.java 8584 2006-08-10 23:06:37Z duns $
 */
public class TTFCMapTable extends TTFTable
{

    public class EncodingTable
    {
        public int platformID;

        public int encodingID;

        public long offset;

        public int format;

        public int length;

        public int version;

        public TableFormat tableFormat;

        public void readHeader() throws IOException
        {
            platformID = ttf.readUShort();
            encodingID = ttf.readUShort();
            offset = ttf.readULong();
        }

        public void readBody() throws IOException
        {
            ttf.seek(offset);
            format = ttf.readUShort();
            length = ttf.readUShort();
            version = ttf.readUShort();
            switch (format)
            {
                case 0:
                    tableFormat = new TableFormat0();
                    break;
                case 4:
                    tableFormat = new TableFormat4();
                    break;
                case 2:
                case 6:
                    System.err.println("Unimplementet encoding table format: " + format);
                    break;
                default:
                    System.err.println("Illegal value for encoding table format: " + format);
                    break;
            }
            if (tableFormat != null)
                tableFormat.read();
        }

        public String toString()
        {
            String str = "[encoding] PID:" + platformID + " EID:" + encodingID + " format:"
                + format + " v" + version
                + (tableFormat != null ? tableFormat.toString() : " [no data read]");
            return str;
        }
    }

    public abstract class TableFormat
    {
        public abstract void read() throws IOException;

        public abstract int getGlyphIndex(int character);
    }

    public class TableFormat0 extends TableFormat
    {

        public int[] glyphIdArray = new int[256];

        public void read() throws IOException
        {
            for (int i = 0; i < glyphIdArray.length; i++)
                glyphIdArray[i] = ttf.readByte();
        }

        public String toString()
        {
            String str = "";
            for (int i = 0; i < glyphIdArray.length; i++)
            {
                if (i % 16 == 0)
                    str += "\n    " + Integer.toHexString(i / 16) + "x: ";
                String number = glyphIdArray[i] + "";
                while (number.length() < 3)
                    number = " " + number;
                str += number + " ";
            }
            return str;
        }

        public int getGlyphIndex(int character)
        {
            return glyphIdArray[character];
        }
    }

    public class TableFormat4 extends TableFormat
    {

        public int segCount;

        public int[] endCount, startCount, idRangeOffset;

        public short[] idDelta; // could be int (ushort) as well

        public void read() throws IOException
        {
            segCount = ttf.readUShort() / 2;
            // dump the next three ushorts to /dev/null as they guy
            // who invented them really must have drunk a lot
            ttf.readUShort();
            ttf.readUShort();
            ttf.readUShort();

            // endCount = readFFFFTerminatedUShortArray();
            endCount = ttf.readUShortArray(segCount);
            int reservedPad = ttf.readUShort();
            if (reservedPad != 0)
                System.err.println("reservedPad not 0, but " + reservedPad + ".");

            startCount = ttf.readUShortArray(endCount.length);
            // the deltas should be unsigned, but due to
            // modulo arithmetic it makes no difference
            idDelta = ttf.readShortArray(endCount.length);
            idRangeOffset = ttf.readUShortArray(endCount.length);
        }

        public String toString()
        {
            String str = "\n   " + endCount.length + " sections:";
            for (int i = 0; i < endCount.length; i++)
                str += "\n    " + startCount[i] + " to " + endCount[i] + " : " + idDelta[i] + " ("
                    + idRangeOffset[i] + ")";
            return str;
        }

        public int getGlyphIndex(int character)
        {
            return 0;
        }
    }

    public int version;

    public EncodingTable encodingTable[];

    public String getTag()
    {
        return "cmap";
    }

    public void readTable() throws IOException
    {
        version = ttf.readUShort();
        encodingTable = new EncodingTable[ttf.readUShort()];
        for (int i = 0; i < encodingTable.length; i++)
        {
            encodingTable[i] = new EncodingTable();
            encodingTable[i].readHeader();
        }
        for (int i = 0; i < encodingTable.length; i++)
        {
            encodingTable[i].readBody();
        }
    }

    public String toString()
    {
        String str = super.toString() + " v" + version;
        for (int i = 0; i < encodingTable.length; i++)
            str += "\n  " + encodingTable[i];
        return str;
    }
}
