using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
 
// Creation date: 11.10.2002
// Checked: xx.05.2002
// Author: Otto Mayer (mot@root.ch)
// Version: 1.01

// Report.NET copyright 2002-2004 root-software ag, Bürglen Switzerland - O. Mayer, S. Spirig, R. Gartenmann, all rights reserved
// This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation, version 2.1 of the License.
// This library 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 Lesser General Public License for more details. You
// should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA www.opensource.org/licenses/lgpl-license.html

namespace Root.Reports {
  /// <summary>Type 1 Font Data</summary>
  /// <remarks>This class is based on the "Adobe Font Metrics File Format Specification" <see href="http://partners.adobe.com/asn/developer/pdfs/tn/5004.AFM_Spec.pdf"/></remarks>
  public class Type1FontData : FontData {
    //----------------------------------------------------------------------------------------------------x
    #region AFM Font Information
    //----------------------------------------------------------------------------------------------------x

    /// <summary>Font metrics version</summary>
    /// <example><code>StartFontMetrics 4.1</code></example>
    internal readonly String sFontMetricsVersion;

    /// <summary>Metric sets</summary>
    /// <example><code>MetricsSets 0</code></example>
    internal readonly Int32 iMetricsSets = 0;

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -x
    // Global Font Information

    /// <summary>Font name</summary>
    /// <example><code>FontName Times-Roman</code></example>
    internal readonly String sFontName;

    /// <summary>Full name</summary>
    /// <example><code></code>FullName Times Roman</example>
    internal readonly String sFullName;

    /// <summary>Family name</summary>
    /// <example><code>FamilyName Times</code></example>
    internal readonly String sFamilyName;

    /// <summary>Weight</summary>
    /// <example><code>Weight Roman</code></example>
    internal readonly String sWeight;

    /// <summary>Font box</summary>
    /// <example><code>FontBBox -168 -218 1000 898</code></example>
    internal readonly Single fFontBBox_llx = Single.NaN;
    internal readonly Single fFontBBox_lly = Single.NaN;
    internal readonly Single fFontBBox_urx = Single.NaN;
    internal readonly Single fFontBBox_ury = Single.NaN;

    /// <summary>Version</summary>
    /// <example><code>Version 002.000</code></example>
    internal readonly String sVersion;

    /// <summary>Notice</summary>
    /// <example><code>Notice Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated ...</code></example>
    internal readonly String sNotice;

    /// <summary>Encoding scheme</summary>
    /// <remarks>
    /// The encoding is 'StandardEncoding' or 'AdobeStandardEncoding' for a font that can be totally encoded according to the characters names.
    /// For all other names the font is treated as symbolic.
    /// </remarks>
    /// <example><code>EncodingScheme AdobeStandardEncoding</code></example>
    internal readonly String sEncodingScheme;

    // internal readonly Int32 iMappingScheme;  // not present with base fonts

    // internal readonly Int32 iEscChar;  // only for MappingScheme 3

    /// <summary>Character set</summary>
    /// <example><code>CharacterSet ExtendedRoman</code></example>
    internal readonly String sCharacterSet;

    // internal readonly Int32 iCharacters;

    /// <summary>Base font flag</summary>
    /// <example><code>IsBaseFont true</code></example>
    internal readonly Boolean bIsBaseFont = true;

    // internal readonly Single fVVector_Origin0;  // only for MetricsSets 2

    // internal readonly Single fVVector_Origin1;  // only for MetricsSets 2

    // internal readonly Boolean bIsFixedV;  // only for MetricsSets 2

    /// <summary>Cap height</summary>
    /// <example><code>CapHeight 662</code></example>
    internal readonly Single fCapHeight = Single.NaN;

    /// <summary>X height</summary>
    /// <example><code>XHeight 450</code></example>
    internal readonly Single fXHeight = Single.NaN;
    
    /// <summary>Ascender</summary>
    /// <example><code>Ascender 683</code></example>
    internal readonly Single fAscender = Single.NaN;
    
    /// <summary>Descender</summary>
    /// <example><code>Descender -217</code></example>
    internal readonly Single fDescender = Single.NaN;
    
    /// <summary>Standard horizontal width</summary>
    /// <example><code>StdHW 28</code></example>
    internal readonly Single fStdHW = Single.NaN;
    
    /// <summary>Standard vertical width</summary>
    /// <example><code>StdVW 84</code></example>
    internal readonly Single fStdVW = Single.NaN;

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -x
    // Writing Direction Information

    // internal readonly Int32 iStartDirection;

    /// <summary>Underline position</summary>
    /// <example><code>UnderlinePosition -100</code></example>
    internal readonly Single fUnderlinePosition = Single.NaN;

    /// <summary>Underline thickness</summary>
    /// <example><code>UnderlineThickness 50</code></example>
    internal readonly Single fUnderlineThickness = Single.NaN;

    /// <summary>Italic angle</summary>
    /// <example><code>ItalicAngle 0</code></example>
    internal readonly Single fItalicAngle = Single.NaN;
    
    // internal readonly Single fCharWidth_x;
    
    // internal readonly Single fCharWidth_y;
    
    /// <summary><see langword="true"/> if all the characters have the same width.</summary>
    /// <example><code>IsFixedPitch false</code></example>
    internal readonly Boolean bIsFixedPitch = false;

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -x
    // Individual Character Metrics

    /// <summary>Number of character metrics entries</summary>
    internal readonly Int32 iCharMetricsCount;

    /// <summary>Character metrics definition array</summary>
    private readonly CharMetrics[] aCharMetrics;

    //internal readonly Int32 iKernDataCount;

    //internal readonly Int32 iCompositesCount;
    #endregion

    //----------------------------------------------------------------------------------------------------x
    internal static readonly Char[] acDelimiterSemicolon = {';'};

    private static readonly Char[] acDelimiterToken = {' ', '\t'};

    //----------------------------------------------------------------------------------------------------x
    /// <summary>Creates the type 1 font data object</summary>
    /// <param name="stream">AFM definition stream</param>
    /// <param name="style"></param>
    internal Type1FontData(Stream stream, Style style /*, Encoding encoding, Boolean bEmbedded*/ /*, byte ttfAfm[], byte pfb[]*/)
      : base(style, FontData.Encoding.Cp1252, true/*encoding, bEmbedded, bCached*/) {
      //Boolean bBuiltinFont14 = bIsBuiltinFont14();
      StreamReader streamReader = new StreamReader(stream);
      try {
        // Header
        String sLine = streamReader.ReadLine();
        if (sLine == null || !sLine.StartsWith("StartFontMetrics")) {
          throw new ReportException("Token [StartFontMetrics] expected in AFM file");
        }

        // general information
        do {
          if (sLine.StartsWith("Comment")) {
            goto NextLine;
          }
          String[] asToken = sLine.Split(acDelimiterToken, 5);
          if (asToken.Length == 0) {
            goto NextLine;
          }
          switch (asToken[0]) {
            case "StartFontMetrics": { sFontMetricsVersion = asToken[1];  break; }
            case "MetricsSets": { iMetricsSets = Int32.Parse(asToken[1]);  break; }
            case "FontName": { sFontName = asToken[1];  break; }
            case "FullName": { sFullName = asToken[1];  break; }
            case "FamilyName": { sFamilyName = asToken[1];  break; }
            case "Weight": { sWeight = asToken[1];  break; }
            case "FontBBox": {
              fFontBBox_llx = Single.Parse(asToken[1]);
              fFontBBox_lly = Single.Parse(asToken[2]);
              fFontBBox_urx = Single.Parse(asToken[3]);
              fFontBBox_ury = Single.Parse(asToken[4]);
              break;
            }
            case "Version": { sVersion = asToken[1];  break; }
            case "Notice": { sNotice = sLine.Substring(7);  break; }
            case "EncodingScheme": { sEncodingScheme = asToken[1];  break; }
            case "CharacterSet": { sCharacterSet = asToken[1];  break; }
            case "IsBaseFont": { bIsBaseFont = Boolean.Parse(asToken[1]);  break; }
            case "CapHeight": { fCapHeight = Single.Parse(asToken[1]);  break; }
            case "XHeight": { fXHeight = Single.Parse(asToken[1]);  break; }
            case "Ascender": { fAscender = Single.Parse(asToken[1]);  break; }
            case "Descender": { fDescender = Single.Parse(asToken[1]);  break; }
            case "StdHW": { fStdHW = Single.Parse(asToken[1]);  break; }
            case "StdVW": { fStdVW = Single.Parse(asToken[1]);  break; }
            case "UnderlinePosition": { fUnderlinePosition = Single.Parse(asToken[1]);  break; }
            case "UnderlineThickness": { fUnderlineThickness  = Single.Parse(asToken[1]);  break; }
            case "ItalicAngle": { fItalicAngle = Single.Parse(asToken[1]);  break; }
            case "IsFixedPitch": { bIsFixedPitch = Boolean.Parse(asToken[1]);  break; }
            case "StartCharMetrics": { iCharMetricsCount = Int32.Parse(asToken[1]);  goto EndGeneralInfo; }
            default: {
              Debug.Fail("Unknown token [" + asToken[0] + "] in AFM file: " + sFontName);
              break;
            }
          }
         NextLine:
          sLine = streamReader.ReadLine();
        } while (sLine != null);
      EndGeneralInfo:

        // check for required fields
        Debug.Assert(sFontMetricsVersion != null);
        Debug.Assert(iMetricsSets == 0);
        if (sFontName == null) {
          throw new ReportException("FontName is required in AFM file: " + sFontName);
        }
        if (Single.IsNaN(fFontBBox_llx) || Single.IsNaN(fFontBBox_lly) || Single.IsNaN(fFontBBox_urx) || Single.IsNaN(fFontBBox_ury)) {
          throw new ReportException("FontBBox is required in AFM file: " + sFamilyName);
        }

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -x
        // character metrics
        if (iCharMetricsCount <= 0) {
          throw new ReportException("Character metrics expected in AFM file: " + sFontName);
        }
        aCharMetrics = new CharMetrics[AdobeFromUnicode.aiAdobeFromUnicode.Length];  // !!!
        for (Int32 iLine = 0;  iLine < iCharMetricsCount;  iLine++) {
          sLine = streamReader.ReadLine();
          if (sLine == null) {
            throw new ReportException("More character metrics definitions expected in AFM file: " + sFontName);
          }
          new CharMetrics(sLine, this);
        }
        sLine = streamReader.ReadLine();
        if (!sLine.StartsWith("EndCharMetrics")) {
          throw new ReportException("Token [EndCharMetrics] expected in AFM file: " + sFontName);
        }

        aCharMetrics[173] = aCharMetrics[45];  // same character definition

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -x
        // kerning data
        sLine = streamReader.ReadLine();
        //if (!sLine.StartsWith("StartKernData")) {
        //  throw new ReportException("Token [StartKernData] expected in AFM file: " + sFontName);
        //}
      }
      finally {
        streamReader.Close();
      }
    }

    //----------------------------------------------------------------------------------------------------x
    // <summary></summary>
    // <returns></returns>
    //private Boolean bIsBuiltinFont14() {
    //  return "Courier,Helvetica,Symbol,Times-Roman,ZapfDingbats".IndexOf(sName) >= 0;
    //}

    //====================================================================================================x
    /// <summary>AFM Character Metrics</summary>
    /// <example><code>C 102 ; WX 333 ; N f ; B 20 0 383 683 ; L i fi ; L l fl ;</code></example>
    public class CharMetrics {
      /// <summary>Character code</summary>
      internal Int32 iCharacterCode = -1;

      /// <summary>Horizontal character width for writing direction 0</summary>
      internal Single fWidthX = 250;

      /// <summary>Character name</summary>
      internal String sName;
      
      /// <summary>Font box</summary>
      internal Single fBBox_llx;
      internal Single fBBox_lly;
      internal Single fBBox_urx;
      internal Single fBBox_ury;
      
      /// <summary>Ligature sequence</summary>
      internal ArrayList al_Ligature;

      //----------------------------------------------------------------------------------------------------x
      /// <summary></summary>
      /// <param name="sLine"></param>
      /// <param name="type1FontData"></param>
      internal CharMetrics(String sLine, Type1FontData type1FontData) {
        String[] asLineToken = sLine.Split(Type1FontData.acDelimiterSemicolon, 10);
        if (asLineToken.Length <= 2) {
          throw new ReportException("Invalid character metrics definition in AFM file: " + type1FontData.sFontName);
        }
        for (Int32 iExpr = 0;  iExpr < asLineToken.Length;  iExpr++) {
          if (asLineToken[iExpr].Length == 0) {
            continue;
          }
          String[] asToken = asLineToken[iExpr].Trim().Split(acDelimiterToken, 5);
          switch (asToken[0]) {
            case "C": { iCharacterCode = Int32.Parse(asToken[1], CultureInfo.InvariantCulture);  break; }
            case "CH": { iCharacterCode = Int32.Parse(asToken[1], System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture);  break; }
            case "WX":  case "W0X": { fWidthX = Single.Parse(asToken[1], CultureInfo.InvariantCulture);  break; }
            case "N": { sName = asToken[1];  break; }
            case "B": {
              fBBox_llx = Single.Parse(asToken[1]);
              fBBox_lly = Single.Parse(asToken[2]);
              fBBox_urx = Single.Parse(asToken[3]);
              fBBox_ury = Single.Parse(asToken[4]);
              break;
            }
            case "L": {
              if (al_Ligature == null) {
                al_Ligature = new ArrayList(10);
              }
              al_Ligature.Add(new Ligature(asToken[1], asToken[2]));
              break;
            }
            default: {
              Debug.Fail("Unknown token [" + asToken[0] + "] in AFM file: " + type1FontData.sFontName);
              break;
            }
          }
        }

        // find index
        Int32 iIndex = iCharacterCode;
        if (type1FontData.sFontName != "Symbol" && type1FontData.sFontName != "ZapfDingbats") {
          switch (iIndex) {
            case  39:  iIndex =   0;  break;  // quoteright
            case  96:  iIndex =   0;  break;  // quoteleft
            case 127:  iIndex =  -1;  break;  // does not exist!
            case 128:  iIndex =  -1;  break;  // does not exist!
            case 129:  iIndex =  -1;  break;  // does not exist!
            case 130:  iIndex =  -1;  break;  // does not exist!
            case 131:  iIndex =  -1;  break;  // does not exist!
            case 132:  iIndex =  -1;  break;  // does not exist!
            case 133:  iIndex =  -1;  break;  // does not exist!
            case 134:  iIndex =  -1;  break;  // does not exist!
            case 135:  iIndex =  -1;  break;  // does not exist!
            case 136:  iIndex =  -1;  break;  // does not exist!
            case 137:  iIndex =  -1;  break;  // does not exist!
            case 138:  iIndex =  -1;  break;  // does not exist!
            case 139:  iIndex =  -1;  break;  // does not exist!
            case 140:  iIndex =  -1;  break;  // does not exist!
            case 141:  iIndex =  -1;  break;  // does not exist!
            case 142:  iIndex =  -1;  break;  // does not exist!
            case 143:  iIndex =  -1;  break;  // does not exist!
            case 144:  iIndex =  -1;  break;  // does not exist!
            case 145:  iIndex =  -1;  break;  // does not exist!
            case 146:  iIndex =  -1;  break;  // does not exist!
            case 147:  iIndex =  -1;  break;  // does not exist!
            case 148:  iIndex =  -1;  break;  // does not exist!
            case 149:  iIndex =  -1;  break;  // does not exist!
            case 150:  iIndex =  -1;  break;  // does not exist!
            case 151:  iIndex =  -1;  break;  // does not exist!
            case 152:  iIndex =  -1;  break;  // does not exist!
            case 153:  iIndex =  -1;  break;  // does not exist!
            case 154:  iIndex =  -1;  break;  // does not exist!
            case 155:  iIndex =  -1;  break;  // does not exist!
            case 156:  iIndex =  -1;  break;  // does not exist!
            case 157:  iIndex =  -1;  break;  // does not exist!
            case 158:  iIndex =  -1;  break;  // does not exist!
            case 159:  iIndex =  -1;  break;  // does not exist!
            case 160:  iIndex =  -1;  break;  // does not exist!
            case 164:  iIndex =   0;  break;  // fraction "/"
            case 166:  iIndex =   0;  break;  // florin
            case 168:  iIndex = 164;  break;  // currency "¤"
            case 169:  iIndex =  39;  break;  // quotesingle "'"
            case 170:  iIndex =   0;  break;  // quotedblleft
            case 172:  iIndex =   0;  break;  // guilsinglleft
            case 173:  iIndex =   0;  break;  // guilsinglright
            case 174:  iIndex =   0;  break;  // fi
            case 175:  iIndex =   0;  break;  // fl
            case 176:  iIndex =  -1;  break;  // does not exist!
            case 177:  iIndex =   0;  break;  // endash "-"
            case 178:  iIndex =   0;  break;  // dagger
            case 179:  iIndex =   0;  break;  // daggerdbl
            case 180:  iIndex = 183;  break;  // periodcentered
            case 183:  iIndex =   0;  break;  // bullet
            case 184:  iIndex =   0;  break;  // quotesinglbase
            case 185:  iIndex =   0;  break;  // quotedblbase
            case 186:  iIndex =   0;  break;  // quotedblright
            case 188:  iIndex =   0;  break;  // ellipsis
            case 189:  iIndex =   0;  break;  // perthousand
            case 190:  iIndex =  -1;  break;  // does not exist!
            case 192:  iIndex =  -1;  break;  // does not exist!
            case 193:  iIndex =  96;  break;  // grave "`"
            case 194:  iIndex = 180;  break;  // acute "´"
            case 195:  iIndex =   0;  break;  // circumflex "^"
            case 196:  iIndex =   0;  break;  // tilde "~"
            case 197:  iIndex = 175;  break;  // macron
            case 198:  iIndex =   0;  break;  // breve
            case 199:  iIndex =   0;  break;  // dotaccent
            case 200:  iIndex = 168;  break;  // dieresis "¨"
            case 201:  iIndex =  -1;  break;  // does not exist!
            case 202:  iIndex =   0;  break;  // ring
            case 203:  iIndex = 184;  break;  // cedilla "¨"
            case 204:  iIndex =  -1;  break;  // does not exist!
            case 205:  iIndex =   0;  break;  // hungarumlaut
            case 206:  iIndex =   0;  break;  // ogonek
            case 207:  iIndex =   0;  break;  // caron
            case 208:  iIndex =   0;  break;  // emdash
            case 209:  iIndex =  -1;  break;  // does not exist!
            case 210:  iIndex =  -1;  break;  // does not exist!
            case 211:  iIndex =  -1;  break;  // does not exist!
            case 212:  iIndex =  -1;  break;  // does not exist!
            case 213:  iIndex =  -1;  break;  // does not exist!
            case 214:  iIndex =  -1;  break;  // does not exist!
            case 215:  iIndex =  -1;  break;  // does not exist!
            case 216:  iIndex =  -1;  break;  // does not exist!
            case 217:  iIndex =  -1;  break;  // does not exist!
            case 218:  iIndex =  -1;  break;  // does not exist!
            case 219:  iIndex =  -1;  break;  // does not exist!
            case 220:  iIndex =  -1;  break;  // does not exist!
            case 221:  iIndex =  -1;  break;  // does not exist!
            case 222:  iIndex =  -1;  break;  // does not exist!
            case 223:  iIndex =  -1;  break;  // does not exist!
            case 224:  iIndex =  -1;  break;  // does not exist!
            case 225:  iIndex = 198;  break;  // AE
            case 226:  iIndex =  -1;  break;  // does not exist!
            case 227:  iIndex = 170;  break;  // ordfeminine
            case 228:  iIndex =  -1;  break;  // does not exist!
            case 229:  iIndex =  -1;  break;  // does not exist!
            case 230:  iIndex =  -1;  break;  // does not exist!
            case 231:  iIndex =  -1;  break;  // does not exist!
            case 232:  iIndex =   0;  break;  // Lslash
            case 233:  iIndex = 216;  break;  // Oslash
            case 234:  iIndex =   0;  break;  // OE
            case 235:  iIndex = 186;  break;  // ordmasculine
            case 236:  iIndex =  -1;  break;  // does not exist!
            case 237:  iIndex =  -1;  break;  // does not exist!
            case 238:  iIndex =  -1;  break;  // does not exist!
            case 239:  iIndex =  -1;  break;  // does not exist!
            case 240:  iIndex =  -1;  break;  // does not exist!
            case 241:  iIndex = 230;  break;  // ae
            case 242:  iIndex =  -1;  break;  // does not exist!
            case 243:  iIndex =  -1;  break;  // does not exist!
            case 244:  iIndex =  -1;  break;  // does not exist!
            case 245:  iIndex =   0;  break;  // dotlessi
            case 246:  iIndex =  -1;  break;  // does not exist!
            case 247:  iIndex =  -1;  break;  // does not exist!
            case 248:  iIndex =   0;  break;  // lslash
            case 249:  iIndex = 248;  break;  // oslash
            case 250:  iIndex =   0;  break;  // oe
            case 251:  iIndex = 223;  break;  // germandbls
            case -1: {
              switch (sName) {
                case "brokenbar":      iIndex = 166;  break;
                case "copyright":      iIndex = 169;  break;
                case "logicalnot":     iIndex = 172;  break;
                case "registered":     iIndex = 174;  break;
                case "degree":         iIndex = 176;  break;
                case "plusminus":      iIndex = 177;  break;
                case "twosuperior":    iIndex = 178;  break;
                case "threesuperior":  iIndex = 179;  break;
                case "mu":             iIndex = 181;  break;
                case "onesuperior":    iIndex = 185;  break;
                case "onequarter":     iIndex = 188;  break;
                case "onehalf":        iIndex = 189;  break;
                case "threequarters":  iIndex = 190;  break;
                case "Agrave":         iIndex = 192;  break;
                case "Aacute":         iIndex = 193;  break;
                case "Acircumflex":    iIndex = 194;  break;
                case "Atilde":         iIndex = 195;  break;
                case "Adieresis":      iIndex = 196;  break;
                case "Aring":          iIndex = 197;  break;
                case "Ccedilla":       iIndex = 199;  break;
                case "Egrave":         iIndex = 200;  break;
                case "Eacute":         iIndex = 201;  break;
                case "Ecircumflex":    iIndex = 202;  break;
                case "Edieresis":      iIndex = 203;  break;
                case "Igrave":         iIndex = 204;  break;
                case "Iacute":         iIndex = 205;  break;
                case "Icircumflex":    iIndex = 206;  break;
                case "Idieresis":      iIndex = 207;  break;
                case "Eth":            iIndex = 208;  break;
                case "Ntilde":         iIndex = 209;  break;
                case "Ograve":         iIndex = 210;  break;
                case "Oacute":         iIndex = 211;  break;
                case "Ocircumflex":    iIndex = 212;  break;
                case "Otilde":         iIndex = 213;  break;
                case "Odieresis":      iIndex = 214;  break;
                case "multiply":       iIndex = 215;  break;
                case "Ugrave":         iIndex = 217;  break;
                case "Uacute":         iIndex = 218;  break;
                case "Ucircumflex":    iIndex = 219;  break;
                case "Udieresis":      iIndex = 220;  break;
                case "Yacute":         iIndex = 221;  break;
                case "Thorn":          iIndex = 222;  break;
                case "agrave":         iIndex = 224;  break;
                case "aacute":         iIndex = 225;  break;
                case "acircumflex":    iIndex = 226;  break;
                case "atilde":         iIndex = 227;  break;
                case "adieresis":      iIndex = 228;  break;
                case "aring":          iIndex = 229;  break;
                case "ccedilla":       iIndex = 231;  break;
                case "egrave":         iIndex = 232;  break;
                case "eacute":         iIndex = 233;  break;
                case "ecircumflex":    iIndex = 234;  break;
                case "edieresis":      iIndex = 235;  break;
                case "igrave":         iIndex = 236;  break;
                case "iacute":         iIndex = 237;  break;
                case "icircumflex":    iIndex = 238;  break;
                case "idieresis":      iIndex = 239;  break;
                case "eth":            iIndex = 240;  break;
                case "ntilde":         iIndex = 241;  break;
                case "ograve":         iIndex = 242;  break;
                case "oacute":         iIndex = 243;  break;
                case "ocircumflex":    iIndex = 244;  break;
                case "otilde":         iIndex = 245;  break;
                case "odieresis":      iIndex = 246;  break;
                case "divide":         iIndex = 247;  break;
                case "ugrave":         iIndex = 249;  break;
                case "uacute":         iIndex = 250;  break;
                case "ucircumflex":    iIndex = 251;  break;
                case "udieresis":      iIndex = 252;  break;
                case "yacute":         iIndex = 253;  break;
                case "thorn":          iIndex = 254;  break;
                case "ydieresis":      iIndex = 255;  break;
                case "Amacron":        iIndex = 256;  break;

                case "Abreve":         iIndex = 258;  break;
                case "abreve":         iIndex = 259;  break;
                case "Aogonek":        iIndex = 260;  break;
                case "aogonek":        iIndex = 261;  break;
                case "Cacute":         iIndex = 262;  break;
                case "cacute":         iIndex = 263;  break;

                case "Ccaron":         iIndex = 268;  break;
                case "ccaron":         iIndex = 269;  break;
                case "Dcaron":         iIndex = 270;  break;
                case "dcaron":         iIndex = 271;  break;
                case "Dcroat":         iIndex = 272;  break;
                case "dcroat":         iIndex = 273;  break;
                case "Emacron":        iIndex = 274;  break;
                case "emacron":        iIndex = 275;  break;

                case "Edotaccent":     iIndex = 278;  break;
                case "edotaccent":     iIndex = 279;  break;
                case "Eogonek":        iIndex = 280;  break;
                case "eogonek":        iIndex = 281;  break;
                case "Ecaron":         iIndex = 282;  break;
                case "ecaron":         iIndex = 283;  break;

                case "Gbreve":         iIndex = 286;  break;
                case "gbreve":         iIndex = 287;  break;

                case "Gcommaaccent":   iIndex = 290;  break;
                case "gcommaaccent":   iIndex = 291;  break;
                    
                case "Imacron":        iIndex = 298;  break;
                case "imacron":        iIndex = 299;  break;
                case "Euro":           iIndex = 128;  break;
                default: {
                  iIndex = 0;
                  break;
                }
              }
              break;
            }
          }
        }
        if (iIndex > 0) {
          type1FontData.aCharMetrics[iIndex] = this;
        }
      }
    }

    //====================================================================================================x
    /// <summary>AFM Ligature</summary>
    public struct Ligature {
      /// <summary></summary>
      public String sSuccessor;

      /// <summary></summary>
      public String sLigature;

      /// <summary>
      /// 
      /// </summary>
      /// <param name="sSuccessor"></param>
      /// <param name="sLigature"></param>
      public Ligature(String sSuccessor, String sLigature) {
        this.sSuccessor = sSuccessor;
        this.sLigature = sLigature;
      }
    }

    #region old
    //----------------------------------------------------------------------------------------------------x
    //----------------------------------------------------------------------------------------------------x
    /// <summary>
    /// 
    /// </summary>
    /// <param name="sText"></param>
    /// <returns></returns>
    public Double rWidth(String sText) {
      if (sText.Length == 0) {
        return 0;
      }

      Double rWidth = 0;
      Double rCharSpacing = 0;
      Double rWordSpacing = 0;

      foreach (Char c in sText) {
        Int16 iChar = (Int16)c;
        Type1FontData.CharMetrics acm = afmCharMetrics(iChar);
        if (acm == null) {
          Console.WriteLine("Unknown character [" + c + "/" + iChar + "] in string [" + sText + "].");
        }
        else {
          Debug.Assert(!Single.IsNaN(acm.fWidthX));
          rWidth += acm.fWidthX;
        }
        if (c == ' ') {
          rWidth += rWordSpacing;
        }
      }
      rWidth += (sText.Length - 1) * rCharSpacing;
      return rWidth;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="iUnicode"></param>
    /// <returns></returns>
    public Type1FontData.CharMetrics afmCharMetrics(Int32 iUnicode) {
      if (iUnicode >= aCharMetrics.Length) {
        if (iUnicode == 8364) {
          return aCharMetrics[128];
        }
        return null;
      }
      return aCharMetrics[iUnicode];
    }
    #endregion

  }
}
