/*
    TCFbECustomCommandLineParser.cpp    January 13, 2004.

    Copyright (C) 2003-2005 CFbE Research Group,
    Software Engineering Laboratory,
    Graduate School of Information Science,
    Nara Institute of Science and Technology,
    All rights reserved.

    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, (at your option) or
    any later version.

    This program 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with GNU Emacs; see the file COPYING.  If not, write to the
    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/
//---------------------------------------------------------------------------
#pragma hdrstop

#include "TCFbECustomCommandLineParser.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
// コンストラクタ（argc と argv によってコマンドラインを与える
__fastcall TCFbECustomCommandLineParser::TCFbECustomCommandLineParser(int argc, char* argv[])
{
    this->ErrorCode = 0;

    // コマンドライン文字数が 1024 文字以上
    if (StrLen(CmdLine) >= 1024) {
        this->ErrorCode = 6;
        return;
    }

    this->LearningDataFileNameList = new TStringList();
    this->FOptionList = new TStringList();
    this->TargetColumnLabelList = new TStringList;

    if (argc > 0) {
        for (int i = 0; i < argc; i++) {
            this->FOptionList->Add(AnsiString(argv[i]));
        }
    } else {
        for (int i = 0; i < ParamCount(); i++) {
            this->FOptionList->Add(ParamStr(i));
        }
    }

    try {
        // -h, --help パラメータの検査
        if (this->IsEmpty() || this->IsEnableOption("-h", "--help")) {
            this->HelpEnabled = true;
            return;
        }
        this->HelpEnabled = false;

        // -l, --learning パラメータの検査
        this->LearningDataFileNameList->DelimitedText = this->GetValueString("-l", "--learning");
        if (this->LearningDataFileNameList->Count <= 0) {
            this->ErrorCode = 1;
            return;
        }
        for (int k = 0; k < this->LearningDataFileNameList->Count; k++) {
            if (!FileExists(this->LearningDataFileNameList->Strings[k])) {
                this->ErrorCode = 2;
                this->ErrorParameter = this->LearningDataFileNameList->Strings[k];
                return;
            }
        }

        // -s, --similarity パラメータの検査
        this->SimilarityComputationName = this->GetValueString("-s", "--similarity");
        if (this->SimilarityComputationName.IsEmpty()) {
            this->ErrorCode = 4;
            return;
        } else {
            TCFbESimilarityComputationAlgorithm*    SCA = this->CreateSimilarityComputationAlgorithm(this->SimilarityComputationName);
            if (SCA == NULL) {
                this->ErrorCode = -2;
                this->ErrorParameter = this->SimilarityComputationName;
                return;
            }
            delete SCA;
        }

        // -n, --normalize パラメータの検査
        AnsiString NormalizeMethod = this->GetValueString("-n", "--normalize");
        if (NormalizeMethod.IsEmpty() || (NormalizeMethod.AnsiCompareIC("value") == 0)) {
            this->ValueBase = vbValue;
        } else if (NormalizeMethod.AnsiCompareIC("standardize") == 0) {
            this->ValueBase = vbStandardizedValue;
        } else if (NormalizeMethod.AnsiCompareIC("normalize") == 0) {
            this->ValueBase = vbNormalizedValue;
        } else if (NormalizeMethod.AnsiCompareIC("order") == 0) {
            this->ValueBase = vbOrder;
        } else {
            this->ErrorCode = -4;
            this->ErrorParameter = NormalizeMethod;
            return;
        }

        // -i, --itembased パラメータの検査
        if (this->IsEnableOption("-i", "--itembased")) {
            this->AlgorithmBase = abColumn;
        } else {
            this->AlgorithmBase = abRow;
        }

        // -t, --target パラメータの検査
        this->TargetColumnLabelList->DelimitedText = this->GetValueString("-t", "--target");

        // -d,--default パラメータの検査
        AnsiString DefaultString = this->GetValueString("-d", "--default");
        if (DefaultString.IsEmpty()) {
            this->DefaultValueEnabled = false;
            this->DefaultValue = 0.0;
        } else {
            try {
                this->DefaultValueEnabled = true;
                this->DefaultValue = DefaultString.ToDouble();
            } catch (EConvertError &ece) {
                this->ErrorCode = -14;
                this->ErrorParameter = DefaultString;
                return;
            }
        }

        // -if, --inverse-frequency パラメータの検査
        this->InverseCaseFrequencyEnabled = this->IsEnableOption("-if", "--inverse-frequency");
                                                 
        // -vs, --vw-similarity パラメータの検査
        this->VWSimilarityComputationName = this->GetValueString("-vs", "--vw-similarity");
        if (!this->VWSimilarityComputationName.IsEmpty()) {
            TCFbESimilarityComputationAlgorithm* VWSA = this->CreateSimilarityComputationAlgorithm(this->VWSimilarityComputationName);
            if (VWSA == NULL) {
                this->ErrorCode = -17;
                this->ErrorParameter = this->VWSimilarityComputationName;
                return;
            }
            delete VWSA;
        }

        // -o,--output パラメータの検査
        this->OutputFileName = this->GetValueString("-o", "--output");
        if (!this->OutputFileName.IsEmpty()) {
            AnsiString OutputDirectory = ExtractFileDir(this->OutputFileName);
            if (!DirectoryExists(OutputDirectory)) {
                try {
                    MkDir(OutputDirectory);    // ディレクトリ作成
                } catch (...) {
                    this->ErrorCode = -6;
                    this->ErrorParameter = OutputDirectory;
                    return;
                }
            }
        }

    } catch (...) {
        delete this->TargetColumnLabelList;
        delete this->FOptionList;
        delete this->LearningDataFileNameList;
        throw;
    }
}

//---------------------------------------------------------------------------
__fastcall TCFbECustomCommandLineParser::~TCFbECustomCommandLineParser()
{
    delete this->TargetColumnLabelList;
    delete this->FOptionList;
    delete this->LearningDataFileNameList;
}

//---------------------------------------------------------------------------
// オプションがない
bool __fastcall TCFbECustomCommandLineParser::IsEmpty(void)
{
    return (this->FOptionList->Count == 1);
}

//---------------------------------------------------------------------------
// OptionLabel0, OptionLabel1 のどちらかが OptionList に含まれていれば返す
bool __fastcall TCFbECustomCommandLineParser::IsEnableOption(AnsiString OptionLabel0, AnsiString OptionLabel1)
{
    return (this->FOptionList->IndexOf(OptionLabel0) >= 0)
        || (this->FOptionList->IndexOf(OptionLabel1) >= 0);
}

//---------------------------------------------------------------------------
// OptionLabel0, OptionLabel1 のどちらかと OptionLabel=文字列 という形式で関連付けられた文字列があれば true を返す
bool __fastcall TCFbECustomCommandLineParser::IsEnableValue(AnsiString OptionLabel0, AnsiString OptionLabel1)
{
    return !this->FOptionList->Values[OptionLabel0].IsEmpty() || !this->FOptionList->Values[OptionLabel1].IsEmpty();
}

//---------------------------------------------------------------------------
// OptionLabel0, OptionLabel1 のどちらかと OptionLabel=文字列 という形式で関連付けられた文字列が OptionList にあれば返す
AnsiString __fastcall TCFbECustomCommandLineParser::GetValueString(AnsiString OptionLabel0, AnsiString OptionLabel1)
{
    AnsiString    Buffer = this->FOptionList->Values[OptionLabel0];
    if (Buffer.IsEmpty()) {
        Buffer = this->FOptionList->Values[OptionLabel1];
    }
    return Buffer;
}

//---------------------------------------------------------------------------
// 文字列を与えて，対応する類似度計算アルゴリズムのインスタンスを返す
TCFbESimilarityComputationAlgorithm* __fastcall TCFbECustomCommandLineParser::CreateSimilarityComputationAlgorithm(AnsiString AlgorithmName)
{
    if (AlgorithmName == "CosineSimilarity") {
        return new TCFbECosineSimilarity();

    } else if (AlgorithmName == "AdjustedCosineSimilarityWithAverage") {
        return new TCFbEAdjustedCosineSimilarityWithAverage();

    } else if (AlgorithmName == "AdjustedCosineSimilarityWithMedian") {
        return new TCFbEAdjustedCosineSimilarityWithMedian();

    } else if (AlgorithmName == "CorrelationCoefficientWithAverage") {
        return new TCFbECorrelationCoefficientWithAverage();

    } else if (AlgorithmName == "CorrelationCoefficientWithMedian") {
        return new TCFbECorrelationCoefficientWithMedian();

    } else if (AlgorithmName == "RankCorrelation") {
        return new TCFbERankCorrelation();

    } else if (AlgorithmName == "DistanceSimilarityWithAverage") {
        return new TCFbEDistanceSimilarityWithAverage();

    } else if (AlgorithmName == "DistanceSimilarityWithMedian") {
        return new TCFbEDistanceSimilarityWithMedian();
    }

    return NULL;    // 不正なアルゴリズム名
}

//---------------------------------------------------------------------------
// 文字列を与えて，対応する予測アルゴリズムのインスタンスを返す
TCFbEPredictionAlgorithm* __fastcall TCFbECustomCommandLineParser::CreatePredictionAlgorithm(AnsiString AlgorithmName)
{
    if (AlgorithmName == "WeightedSum") {
        return new TCFbEWeightedSum();

    } else if (AlgorithmName == "AdjustedWeightedSumWithAverageOfColumn") {
        return new TCFbEAdjustedWeightedSumWithAverageOfColumn();

    } else if (AlgorithmName == "AdjustedWeightedSumWithMedianOfColumn") {
        return new TCFbEAdjustedWeightedSumWithMedianOfColumn();

    } else if (AlgorithmName == "AdjustedWeightedSumWithAverageOfNeighbors") {
        return new TCFbEAdjustedWeightedSumWithAverageOfNeighbors();

    } else if (AlgorithmName == "AdjustedWeightedSumWithMedianOfNeighbors") {
        return new TCFbEAdjustedWeightedSumWithMedianOfNeighbors();

    } else if (AlgorithmName == "AdjustedWeightedSumWithAverageOfRow") {
        return new TCFbEAdjustedWeightedSumWithAverageOfRow();

    } else if (AlgorithmName == "AdjustedWeightedSumWithMedianOfRow") {
        return new TCFbEAdjustedWeightedSumWithMedianOfRow();

    } else if (AlgorithmName == "AmplifiedWeightedSumWithAveragedMultiplier") {
        return new TCFbEAmplifiedWeightedSumWithAveragedMultiplier();

    } else if (AlgorithmName == "AmplifiedWeightedSumWithMedianOfMultiplier") {
        return new TCFbEAmplifiedWeightedSumWithMedianOfMultiplier();

    } else if (AlgorithmName == "AmplifiedWeightedSumWithVWWeightedMultiplier") {
        return new TCFbEAmplifiedWeightedSumWithVWWeightedMultiplier();
    }

    return NULL;    // 不正なアルゴリズム名
}

//---------------------------------------------------------------------------

