/*******************************************************************************
 * 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.task;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import blanco.nlpack.generator.csv.io.BlancoCsvIOException;
import blanco.nlpack.generator.csv.io.BlancoNLpackGeneratorResultCsvReader;
import blanco.nlpack.generator.csv.record.BlancoNLpackGeneratorResultCsvRecord;
import blanco.nlpack.generator.task.valueobject.BlancoNLpackGeneratorShowResultProcessInput;

public class BlancoNLpackGeneratorShowResultProcessImpl implements
        BlancoNLpackGeneratorShowResultProcess {

    /**
     * クラスをインスタンス化して処理を実行する際のエントリポイントです。
     * 
     * @param input
     *            処理の入力パラメータ。
     * @return 処理の実行結果。
     * @throws IOException
     *             入出力例外が発生した場合。
     * @throws IllegalArgumentException
     *             入力値に不正が見つかった場合。
     */
    public int execute(final BlancoNLpackGeneratorShowResultProcessInput input)
            throws IOException, IllegalArgumentException {
        final File fileSourceDir = new File(input.getSourcedir());
        if (fileSourceDir.exists() == false) {
            throw new IllegalArgumentException("指定された入力ディレクトリ["
                    + fileSourceDir.getAbsolutePath() + "]が存在しません。");
        }
        if (fileSourceDir.isDirectory() == false) {
            throw new IllegalArgumentException("指定された入力ディレクトリ["
                    + fileSourceDir.getAbsolutePath() + "]はディレクトリではありません。");
        }

        final File[] files = fileSourceDir.listFiles();
        if (files != null) {
            for (int index = 0; index < files.length; index++) {
                if (files[index].isFile()
                        && files[index].getName().endsWith("Result.zip")) {
                    try {
                        new BlancoNLpackGeneratorShowResultProcessImpl()
                                .processEveryFile(files[index]);
                    } catch (BlancoCsvIOException e) {
                        throw new IllegalArgumentException("CSV入力時に例外が発生。", e);
                    }
                }
            }
        }

        return BlancoNLpackGeneratorShowResultBatchProcess.END_SUCCESS;
    }

    protected void processEveryFile(final File fileTarget) throws IOException,
            BlancoCsvIOException {
        int hitCount = 0;
        int missCount = 0;

        final ZipInputStream zipInStream = new ZipInputStream(
                new BufferedInputStream(new FileInputStream(fileTarget)));
        for (;;) {
            final ZipEntry entry = zipInStream.getNextEntry();
            if (entry == null) {
                break;
            }

            if (entry.isDirectory()) {
            } else {
                if (entry.getName().endsWith("-Result.csv")) {
                    final BlancoNLpackGeneratorResultCsvReader reader = new BlancoNLpackGeneratorResultCsvReader(
                            new BufferedReader(new InputStreamReader(
                                    zipInStream)));
                    for (;;) {
                        if (checkValidRecordByUri(reader.getReader()) == false) {
                        } else {
                            final BlancoNLpackGeneratorResultCsvRecord record = reader
                                    .readRecord();
                            if (record == null) {
                                break;
                            }
                            hitCount += record.getReplaceHitCount();
                            missCount += record.getReplaceMissCount();
                        }
                    }
                }
            }
            zipInStream.closeEntry();
        }
        zipInStream.close();

        try {
            final BigDecimal decResult = BigDecimal.valueOf(hitCount * 100)
                    .setScale(2).divide(
                            BigDecimal.valueOf(hitCount + missCount),
                            BigDecimal.ROUND_DOWN);
            System.out.println(decResult.toString() + "% (" + hitCount + "/"
                    + (hitCount + missCount) + ") " + fileTarget.getName());
        } catch (ArithmeticException e) {
            System.out.println("計測不能: " + e.toString());
        }
    }

    private static boolean checkValidRecordByUri(
            final BufferedReader readerInner) throws IOException {
        // "babel: 以外の行は無視します。
        readerInner.mark(8);
        final char[] buf = new char[7];
        final int len = readerInner.read(buf);
        readerInner.reset();

        if (len < 7) {
            // 無視
        } else {
            final String line = new String(buf);
            if (line.startsWith("\"") == false || line.startsWith("\"Symbol")) {
                // 処理不能な行。この行は読み飛ばします。
                readerInner.readLine();
                return false;
            }
        }
        return true;
    }
}
