/*******************************************************************************
 * Copyright (c) 2008 IGA Tosiki, NTT DATA BUSINESS BRAINS Corp.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IGA Tosiki (NTT DATA BUSINESS BRAINS Corp.) - initial API and implementation
 *******************************************************************************/
/*
 * blanco Framework
 * Copyright (C) 2008 NTT DATA BUSINESS BRAINS CORPORATION
 * 
 * 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; either
 * version 2.1 of the License, or (at your option) any later version.
 */
package blanco.nlpack.generator.dictionary;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import blanco.nlpack.generator.BlancoNLpackGeneratorConstants;
import blanco.nlpack.generator.csv.io.BlancoCsvIOException;
import blanco.nlpack.generator.csv.io.BlancoNLpackGeneratorOmitListCsvReader;
import blanco.nlpack.generator.csv.io.BlancoNLpackGeneratorOmitPhraseListCsvReader;
import blanco.nlpack.generator.csv.record.BlancoNLpackGeneratorOmitListCsvRecord;
import blanco.nlpack.generator.csv.record.BlancoNLpackGeneratorOmitPhraseListCsvRecord;
import blanco.nlpack.generator.message.BlancoNLpackGeneratorMessage;

/**
 * 翻訳除外辞書を扱うクラス。
 * 
 * @author IGA Tosiki
 */
public class BlancoNLpackGeneratorOmitDictionary {
    /**
     * メッセージオブジェクト。
     */
    private final BlancoNLpackGeneratorMessage fMsg = new BlancoNLpackGeneratorMessage();

    /**
     * 除外辞書のマップ。
     */
    private Map<String, BlancoNLpackGeneratorOmitListCsvRecord> fOmitMap = null;

    /**
     * ニモーニックのみ変換の除外辞書のマップ。
     */
    private Map<String, BlancoNLpackGeneratorOmitListCsvRecord> fOmitMnemonicOnlyMap = null;

    /**
     * フレーズの除外辞書のマップ。
     */
    private Map<String, BlancoNLpackGeneratorOmitPhraseListCsvRecord> fOmitPhraseMap = null;

    /**
     * 除外辞書をロードします。
     * 
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    private void load() throws IOException {
        System.out.println("babel: omit dictionary: load: begin.");

        final int omitCount = loadOmitDictionary();
        final int omitMnemonicOnlyCount = loadOmitMnemonicOnlyDictionary();
        final int omitPhraseCount = loadOmitPhraseDictionary();

        System.out.println("babel: omit dictionary: load: end: u=" + omitCount
                + ", m=" + omitMnemonicOnlyCount + ", p=" + omitPhraseCount
                + ".");
    }

    private int loadOmitDictionary() throws IOException {
        final InputStream inStream = getClass()
                .getClassLoader()
                .getResourceAsStream(
                        BlancoNLpackGeneratorConstants.FILENAME_OMIT_DICTIONARY);
        if (inStream == null) {
            throw new IllegalArgumentException(
                    fMsg
                            .getMbebmo01(BlancoNLpackGeneratorConstants.FILENAME_OMIT_DICTIONARY));
        }

        fOmitMap = new HashMap<String, BlancoNLpackGeneratorOmitListCsvRecord>();
        int omitCount = 0;

        final BlancoNLpackGeneratorOmitListCsvReader reader = new BlancoNLpackGeneratorOmitListCsvReader(
                new BufferedReader(new InputStreamReader(inStream, "UTF-8")));
        try {
            reader.readRecord();
            for (;;) {
                final BlancoNLpackGeneratorOmitListCsvRecord record = reader
                        .readRecord();
                if (record == null) {
                    break;
                }

                fOmitMap.put(record.getBundleUri(), record);
                omitCount++;
            }
        } catch (BlancoCsvIOException ex) {
            throw new IOException(fMsg.getMbebmo02(ex.toString()));
        } finally {
            reader.close();
        }

        return omitCount;
    }

    private int loadOmitMnemonicOnlyDictionary() throws IOException {
        final InputStream inStream = getClass()
                .getClassLoader()
                .getResourceAsStream(
                        BlancoNLpackGeneratorConstants.FILENAME_OMIT_MNEMONIC_ONLY_DICTIONARY);
        if (inStream == null) {
            // TODO メッセージ番号を別途採番すること。
            throw new IllegalArgumentException(
                    fMsg
                            .getMbebmo01(BlancoNLpackGeneratorConstants.FILENAME_OMIT_MNEMONIC_ONLY_DICTIONARY));
        }

        fOmitMnemonicOnlyMap = new HashMap<String, BlancoNLpackGeneratorOmitListCsvRecord>();
        int omitCount = 0;

        final BlancoNLpackGeneratorOmitListCsvReader reader = new BlancoNLpackGeneratorOmitListCsvReader(
                new BufferedReader(new InputStreamReader(inStream, "UTF-8")));
        try {
            reader.readRecord();
            for (;;) {
                final BlancoNLpackGeneratorOmitListCsvRecord record = reader
                        .readRecord();
                if (record == null) {
                    break;
                }

                fOmitMnemonicOnlyMap.put(record.getBundleUri(), record);
                omitCount++;
            }
        } catch (BlancoCsvIOException ex) {
            // TODO メッセージ番号を別途採番すること。
            throw new IOException(fMsg.getMbebmo02(ex.toString()));
        } finally {
            reader.close();
        }

        return omitCount;
    }

    private int loadOmitPhraseDictionary() throws IOException {
        final InputStream inStream = getClass()
                .getClassLoader()
                .getResourceAsStream(
                        BlancoNLpackGeneratorConstants.FILENAME_OMIT_PHRASE_DICTIONARY);
        if (inStream == null) {
            // TODO メッセージ番号を別途採番すること。
            throw new IllegalArgumentException(
                    fMsg
                            .getMbebmo01(BlancoNLpackGeneratorConstants.FILENAME_OMIT_PHRASE_DICTIONARY));
        }

        fOmitPhraseMap = new HashMap<String, BlancoNLpackGeneratorOmitPhraseListCsvRecord>();
        int omitCount = 0;

        final BlancoNLpackGeneratorOmitPhraseListCsvReader reader = new BlancoNLpackGeneratorOmitPhraseListCsvReader(
                new BufferedReader(new InputStreamReader(inStream, "UTF-8")));
        try {
            // reader.readRecord();
            for (;;) {
                final BlancoNLpackGeneratorOmitPhraseListCsvRecord record = reader
                        .readRecord();
                if (record == null) {
                    break;
                }

                fOmitPhraseMap.put(record.getPhrase(), record);
                omitCount++;
            }
        } catch (BlancoCsvIOException ex) {
            // TODO メッセージ番号を別途採番すること。
            throw new IOException(fMsg.getMbebmo02(ex.toString()));
        } finally {
            reader.close();
        }

        return omitCount;
    }

    /**
     * 与えられたuriが除外対象かどうかをチェックします。
     * 
     * @param uri
     *            URI。
     * @return 除外対象ならtrue。
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    public boolean checkOmitURI(final String uri) throws IOException {
        if (fOmitMap == null) {
            load();
        }

        if (false) {
            // 実験的
            if (uri.endsWith(".properties?key=copyright")
                    || uri.endsWith(".properties?key=license")
                    || uri.endsWith(".properties?key=blurb")
                    || uri.endsWith(".properties?key=featureText")) {
                return true;
            }
        }

        if (fOmitMap.get(uri) != null) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 与えられたuriがニモーニックのみ変換の除外対象かどうかをチェックします。
     * 
     * @param uri
     *            URI。
     * @return 除外対象ならtrue。
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    public boolean checkOmitMnemonicOnlyURI(final String uri)
            throws IOException {
        if (fOmitMnemonicOnlyMap == null) {
            load();
        }

        if (fOmitMnemonicOnlyMap.get(uri) != null) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 与えられたフレーズが除外対象かどうかをチェックします。
     * 
     * @param phrase
     *            フレーズ。
     * @return 除外対象ならtrue。
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    public boolean checkOmitPhrase(final String phrase) throws IOException {
        if (fOmitPhraseMap == null) {
            load();
        }

        if (false) {
            // 実験的

            try {
                // パッケージ名およびクラス名であるかどうかについて類推。
                final Pattern pattern = Pattern
                        .compile("([a-zA-Z]\\w*\\.)+([a-zA-Z]\\w*)");
                final Matcher matcher = pattern.matcher(phrase);
                if (matcher.matches()) {
                    return true;
                }
            } catch (PatternSyntaxException ex) {
                throw new IllegalArgumentException(ex);
            }
        }

        if (fOmitPhraseMap.get(phrase) != null) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 除外対象となる文字列かどうかを判定します。
     * 
     * @param argString
     *            リソースバンドルの文字列。
     * @return 除外対象ならtrue。
     */
    public boolean checkOmitString(final String argString) {
        if (argString == null) {
            return true;
        }

        final String trimmedString = argString.trim();

        int letterCounter = 0;
        for (int index = 0; index < trimmedString.length(); index++) {
            final char look = trimmedString.charAt(index);
            switch (Character.getType(look)) {
            case Character.LOWERCASE_LETTER:
            case Character.UPPERCASE_LETTER:
                // 文字発見。
                letterCounter++;
                if (letterCounter > 1) {
                    return false;
                }
                break;
            }
        }

        return true;
    }

    /**
     * 除外対象となる文字列パターンかどうかを判定します。
     * 
     * @param argString
     *            リソースバンドルの文字列。
     * @return 除外対象ならtrue。
     */
    public boolean checkOmitStringPattern(final String argString) {
        if (argString == null) {
            return true;
        }

        // 画像ファイル名の感が強いものは除外します。
        if (argString.endsWith(".gif") || argString.endsWith(".png")) {
            return true;
        }

        return false;
    }
}
