/*
 * Copyright (c) 2009, Takeyuki Nagao
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the
 * following conditions are met:
 * 
 *  * Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *  * Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *    
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */

package jp.sourceforge.dvibrowser.dvicore.ctx;

import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

import jp.sourceforge.dvibrowser.dvicore.DviException;
import jp.sourceforge.dvibrowser.dvicore.api.CharacterCodeMapper;
import jp.sourceforge.dvibrowser.dvicore.font.LogicalFont;
import jp.sourceforge.dvibrowser.dvicore.util.DviUtils;
import jp.sourceforge.dvibrowser.dvicore.util.csv.CsvCellCodec;
import jp.sourceforge.dvibrowser.dvicore.util.csv.CsvData;
import jp.sourceforge.dvibrowser.dvicore.util.csv.CsvException;


public class Type1DefaultCharacterCodeMapper implements CharacterCodeMapper {
  private static final Logger LOGGER = Logger.getLogger(Type1DefaultCharacterCodeMapper.class.getName());
  
  public static final String ENC_OT1   = "ot1-enc";
  public static final String ENC_CMSY  = "cmsy-enc";
  public static final String ENC_CMMI  = "cmmi-enc";
  public static final String ENC_CMEX  = "cmex-enc";
  public static final String ENC_CMTT  = "cmtt-enc";
  public static final String ENC_T2    = "t2-enc";
  public static final String ENC_CORK  = "cork-enc";
  public static final String ENC_TS1   = "ts1-enc";
  public static final String ENC_YFRAK = "yfrak-enc";
  
  private int [] table = null;

  private final String encName;
  
  public Type1DefaultCharacterCodeMapper(String encName)
  {
    this.encName = encName;
  }
  
  public String mapCharacterCodeToUnicode(LogicalFont logicalFont, int codePoint)
      throws DviException
  {
    try {
      codePoint = mapCodePoint(codePoint);
    } catch (IOException e) {
      DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
      throw new DviException(e);
    } catch (CsvException e) {
      DviUtils.logStackTrace(LOGGER, Level.WARNING, e);
      throw new DviException(e);
    }
    if (Character.charCount(codePoint) == 1) {
      return String.valueOf((char) codePoint);
    } else {
      return new String(Character.toChars(codePoint));
    }
  }

  protected int mapCodePoint(int codePoint) throws IOException, CsvException, DviException {
    initTable();
    if (codePoint < table.length) {
      return table[codePoint];
    }
    return codePoint;
  }
  
  private synchronized void initTable() throws IOException, CsvException, DviException
  {
    if (table == null) {
      doInitTable();
    }
  }
  
  private void doInitTable() throws IOException, CsvException, DviException {
    CsvData<String, Integer> data = new CsvData<String, Integer>(new CsvCellCodec<String, Integer>() {
      public String decodeKey(String s) {
        return s;
      }

      public String encodeKey(String key) {
        return key;
      }

      public Integer decodeValue(String key, String s) {
        return Integer.decode(s);
      }

      public String encodeValue(String key, Integer value) {
        return String.format("0x%x", value.intValue());
      }
    });
    URL url = getEncodingCsvFile(getTexEncodingName());
    data.readFromStream(url.openStream());
    table = new int [128];
    for (int i=0; i<data.getRowCount(); i++) {
      int texchar = data.get(i, "texchar");
      int pfbchar = data.get(i, "pfbchar");
      if (0 <= texchar && texchar < table.length) {
        table[texchar] = pfbchar;
        LOGGER.fine(String.format("MAP: %02x=>%06x\n", texchar, pfbchar));
      } else {
        throw new DviException
          ("texchar value out of range: " + texchar);
      }
    }
  }

  protected URL getEncodingCsvFile(String texEncodingName) {
    String filename = texEncodingName + ".csv";
    URL url = getClass().getResource(filename);
    return url;
  }

  public String getTexEncodingName() {
    return encName;
  }
}
