/*
    TCFbEToolkit.cpp    June 6, 2004.

    Copyright (C) 2003-2004 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 "TCFbEToolkit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
// 以下publicメソッド
//---------------------------------------------------------------------------
// コンストラクタ
__fastcall TCFbEToolkit::TCFbEToolkit()
    : TObject()
{
    this->DebugStringList = new TStringList();  
}

//---------------------------------------------------------------------------
// デストラクタ
__fastcall TCFbEToolkit::~TCFbEToolkit()
{
    if (this->DebugStringList->Count > 0) {
        this->DebugStringList->SaveToFile(ExtractFilePath(Application->ExeName) + "debug.txt");
    }
    delete this->DebugStringList;
}

//---------------------------------------------------------------------------
// ファクトリメソッド，シングルトンとして実装TCFbEToolkitを得たいとき亜このメソッドを叩く
TCFbEToolkit* __fastcall TCFbEToolkit::GetToolkit() {
    if (TCFbEToolkit::Instance == NULL) {    // インスタンスが存在しない
        TCFbEToolkit::Instance = new TCFbEToolkit();
    }
    return TCFbEToolkit::Instance;
}

//---------------------------------------------------------------------------
// ツールキットを解放する
void __fastcall TCFbEToolkit::DeleteToolkit()
{
    if (TCFbEToolkit::Instance != NULL) {    // インスタンスが存在すれば
        delete TCFbEToolkit::Instance;        // 解放する
    }
}

//---------------------------------------------------------------------------
// TList型のコピー
void __fastcall TCFbEToolkit::CopyList(TList* SourceList, TList* DestinationList)
{
    DestinationList->Clear();
    for (int i = 0; i < SourceList->Count; i++) {
        DestinationList->Add(SourceList->Items[i]);
    }
}

//---------------------------------------------------------------------------
// Font0 と Font1 のフォント属性が等しければ true を等しくなければ false を返します．
bool __fastcall TCFbEToolkit::Equals(TFont* Font0, TFont* Font1)
{
    if ((Font0->Name == Font1->Name) && (Font0->Size == Font1->Size) && (Font0->Height == Font1->Height) && (Font0->Color == Font1->Color) && (Font0->Pitch == Font1->Pitch) && (Font0->Charset == Font1->Charset)) {
        return true;
    }
    return false;
}

//---------------------------------------------------------------------------
// Value0 と Value1 を比較する．誤差が ErrorRange 以下なら等しいとする
bool __fastcall TCFbEToolkit::Equals(double Value0, double Value1, double ErrorRange)
{
    return fabs(Value0 - Value1) <= ErrorRange;
}

//---------------------------------------------------------------------------
// アプリケーションが存在するディレクトリにデバッグファイル（"debug.txt"）を出力する
void __fastcall TCFbEToolkit::DebugOutput(AnsiString OutputString)
{
    this->DebugStringList->Add(OutputString);
}

//---------------------------------------------------------------------------
// アプリケーションのプライオリティを変更
void __fastcall TCFbEToolkit::SetApplicationPriority(TThreadPriority Priority)
{
    unsigned long ProcessID = GetCurrentProcessId();
    void* ProcessHandle = OpenProcess(PROCESS_SET_INFORMATION, false, ProcessID);
    void* ThreadHandle = GetCurrentThread();

    switch (Priority) {
        case tpIdle:
            SetPriorityClass(ProcessHandle, IDLE_PRIORITY_CLASS);
            SetThreadPriority(ThreadHandle, THREAD_PRIORITY_IDLE);
            break;

        case tpLowest:
            SetPriorityClass(ProcessHandle, BELOW_NORMAL_PRIORITY_CLASS);
            SetThreadPriority(ThreadHandle, THREAD_PRIORITY_LOWEST);
            break;

        case tpLower:
            SetPriorityClass(ProcessHandle, BELOW_NORMAL_PRIORITY_CLASS);
            SetThreadPriority(ThreadHandle, THREAD_PRIORITY_BELOW_NORMAL);
            break;

        case tpNormal:
            SetPriorityClass(ProcessHandle, NORMAL_PRIORITY_CLASS);
            SetThreadPriority(ThreadHandle, THREAD_PRIORITY_NORMAL);
            break;

        case tpHigher:
            SetPriorityClass(ProcessHandle, ABOVE_NORMAL_PRIORITY_CLASS);
            SetThreadPriority(ThreadHandle, THREAD_PRIORITY_ABOVE_NORMAL);
            break;

        case tpHighest:
            SetPriorityClass(ProcessHandle, HIGH_PRIORITY_CLASS);
            SetThreadPriority(ThreadHandle, THREAD_PRIORITY_HIGHEST);
            break;

        case tpTimeCritical:
            SetPriorityClass(ProcessHandle, REALTIME_PRIORITY_CLASS);
            SetThreadPriority(ThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
            break;
        default:
            break;
    }
}

//---------------------------------------------------------------------------
// DynArray をソートする
// sdAscending    昇順のソート
// sdDescending    降順のソート
void __fastcall TCFbEToolkit::SortDoubleDynArray(TDoubleDynArray& DynArray, TSortDirection Direction)
{
    if (Direction == sdAscending) {
        for (int i = 0; i < DynArray.Length - 1; i++) {
            for (int j = i + 1; j < DynArray.Length; j++) {
                if (DynArray[i] > DynArray[j]) {
                    double Buffer = DynArray[i];
                    DynArray[i] = DynArray[j];
                    DynArray[j] = Buffer;
                }
            }
        }
    } else {
        for (int i = 0; i < DynArray.Length - 1; i++) {
            for (int j = i + 1; j < DynArray.Length; j++) {
                if (DynArray[i] < DynArray[j]) {
                    double Buffer = DynArray[i];
                    DynArray[i] = DynArray[j];
                    DynArray[j] = Buffer;
                }
            }
        }
    }
}

//---------------------------------------------------------------------------
// DynArray の要素の平均値を返す
double __fastcall TCFbEToolkit::GetAverageOfDynArray(TDoubleDynArray& DynArray)
{
    if (DynArray.Length == 0) {
        return 0.0;
    }
    
    double Sum = 0.0;
    for (int k = 0; k < DynArray.Length; k++) {
        Sum += DynArray[k];
    }
    return Sum / DynArray.Length;
}

//---------------------------------------------------------------------------
// DynArray の要素の中間値を返す（DynArray はソートされている必要がある
double __fastcall TCFbEToolkit::GetMedianOfDynArray(TDoubleDynArray& DynArray)
{
    if (DynArray.Length != 0) {
        // Metricsの数が奇数か偶数か
        if ( DynArray.Length % 2 == 1 ) {
            // 奇数の場合、中間要素の値
            return DynArray[(DynArray.Length - 1 ) / 2];
        } else {
            // 偶数の場合、中間要素２個の平均
            return (DynArray[DynArray.Length/2-1] + DynArray[DynArray.Length/2]) / 2.0;
        }
    }

    return 0.0;
}

//---------------------------------------------------------------------------
// CSV形式の文字列をTStringsに分解する
void __fastcall TCFbEToolkit::CsvToStrings(AnsiString str,TStrings *List)
{
    AnsiString tmp;       // 各文字列
    bool quote=false;     // 引用中か

    List->Clear();        // リストのクリア

    for(int i=1;i<=str.Length();i++){
        if(IsDBCSLeadByte(str[i])==TRUE){    //漢字の１バイト目？
            tmp += str[i];
            if(i<str.Length()){
                i++;
                tmp += str[i];
            }
        } else if(this->IsQuote(str[i])){    //引用符
            if(i<str.Length() && this->IsQuote(str[i+1]))
              str+="\"";
            else
              quote=!quote;
        } else if(quote==false && this->IsDelimiter(str[i])) {    //区切り文字
            List->Add(tmp.Trim());
            tmp="";
//        } else if(quote==false && isspace(str[i])) {    //空白(必要かな？)
//            ;
        } else {//その他
            tmp += str[i];
        }
    }

    List->Add(tmp.Trim());
}

//---------------------------------------------------------------------------
// Array の Index1 と Index2 の要素を入替える
void __fastcall TCFbEToolkit::Exchange(TDoubleDynArray& Array, int Index1, int Index2)
{
    double Buffer = Array[Index1];
    Array[Index1] = Array[Index2];
    Array[Index2] = Buffer;
}
                                                 
//---------------------------------------------------------------------------

