#include "AdvModelParamSet.hh"
#include "AdvModelParam.hh"
#include <cfloat>

/**
    AdvModelParamSet
      Function のパラメータを一箇所にまとめたパラメータセットのクラス
*/

/** コンストラクタ　パラメータセットの初期化 */
AdvModelParamSet::AdvModelParamSet()
{
    modify = true;
    m_Params.clear();
}

/** デストラクタ　new したメモリ領域を delete する */
AdvModelParamSet::~AdvModelParamSet()
{
    DeleteAll();
}

/** 新しいパラメータを用意し、パラメータセットに登録する */
AdvModelParam* AdvModelParamSet::NewParam(string s)
{
    modify = true;
    AdvModelParam*  p = new AdvModelParam;
    p->SetName(s);
    m_Params.push_back(p);
    return p;
}

/** 新しいパラメータを用意し、パラメータセットに登録する */
AdvModelParam* AdvModelParamSet::NewParam()
{
    modify = true;
    AdvModelParam*  p = new AdvModelParam;
    m_Params.push_back(p);
    return p;
}

/** 指定したパラメータを削除する(パラメータセットから取り除き、
    メモリを開放する) */
void AdvModelParamSet::DeleteParam(AdvModelParam* p)
{
    modify = true;
    m_Params.remove (p);
    delete p;
}

/** パラメータをすべて削除する(パラメータセットから取り除き、
    メモリを開放する) */
void AdvModelParamSet::DeleteAll()
{
    modify = true;
    list<AdvModelParam*>::iterator it;
    it = m_Params.begin();
    while ( it != m_Params.end() )
    {
        delete (*it);
        ++it;
    }
    m_Params.clear();
}

/** パラメータセットに含まれるフィット対象のパラメータの数を返す */
Int4 AdvModelParamSet::GetNumParam()
{
    if (modify) { PrepareFit(); }
//    return (Int4) m_Params.size();
    return (Int4) m_fitParams.size();
}

/** パラメータセットに含まれるパラメータのうち、fit フラグが立っている
    パラメータの数を返す */
Int4 AdvModelParamSet::GetNumFitParam()
{
    if (modify) { PrepareFit(); }
    return (Int4)m_fitParams.size();
}

/** パラメータセットからフィット対象のパラメータのみをリストアップする
 *  FitIDが同じパラメータは一箇所にまとめる */
void AdvModelParamSet::PrepareFit()
{
    if (!modify) return;

    m_fitParams.clear();
    list<AdvModelParam*>::iterator it;
    vector<vector<AdvModelParam*> >::iterator it2;
    it = m_Params.begin();
    while (it != m_Params.end())
    {
        if ( (*it)->GetFitFlag() ) {        // フィット対象か？
            if ( (*it)->GetFitID() == 0 ) { // FitID = 0 の場合
                vector<AdvModelParam*> v;
                v.push_back( (*it) );
                m_fitParams.push_back( v );
            } else {                  // FitID が 0 でない場合は
                                      // 同一のFitIDがいないか探す
                Int4 found = 0;
                it2 = m_fitParams.begin();
                while (it2 != m_fitParams.end()) {
                    if ( (*it2)[0]->GetFitID() == (*it)->GetFitID() ) {
                        // 同一のFitIDが見つかった場合、同じ場所に入れる
                        (*it2).push_back( (*it) );
                        found = 1;
                        break;
                    }
                    ++it2;
                }
                if (found == 0) {    // 同一のFitIDが見つからない場合、FitID=0と同じ処理
                    vector<AdvModelParam*> v;
                    v.push_back( (*it) );
                    m_fitParams.push_back( v );
                }
            }
        }
        ++it;
    }
    modify = false;
}


/** パラメータセットに含まれるパラメータのうち、fit フラグが立っている
    パラメータの値を vector で返す */
vector<Double> AdvModelParamSet::GetParamValues ()
{
    if (modify) { PrepareFit(); }
    vector<Double> v;
    v.clear();

    vector<vector<AdvModelParam*> >::iterator it2;
    it2 = m_fitParams.begin();
    while (it2 != m_fitParams.end()) {
        Double d = (*it2)[0]->GetFitVal();
        v.push_back( d );
        ++it2;
    }
    return v;
}

/** パラメータセットに含まれるパラメータのうち、fit フラグが立っている
    パラメータの値を変更する。値は vector で与える */
void AdvModelParamSet::SetParamValues (const vector<Double> v)
{
    Int4 iv = 0;
    vector<vector<AdvModelParam*> >::iterator it2;
    it2 = m_fitParams.begin();
    while (it2 != m_fitParams.end())
    {
        vector<AdvModelParam*>::iterator it;
        it = (*it2).begin();
        while (it != (*it2).end())
        {
            (*it)->SetFitVal( v[iv] );  // 同一FitIDには同じ値を渡す
            ++it;
        }
        ++iv;
        ++it2;
    }
}

/** パラメータセットに含まれるパラメータのうち、fit フラグが立っている
    パラメータの値を変更する。値は vector で与える */
void AdvModelParamSet::SetParamValues (const Double v[])
{
    Int4 iv = 0;
    vector<vector<AdvModelParam*> >::iterator it2;
    it2 = m_fitParams.begin();
    while (it2 != m_fitParams.end())
    {
        vector<AdvModelParam*>::iterator it;
        it = (*it2).begin();
        while (it != (*it2).end())
        {
            (*it)->SetFitVal( v[iv] );
            ++it;
        }
        ++iv;
        ++it2;
    }
}

/** パラメータセットに含まれるパラメータのうち、fit フラグが立っている
    パラメータの値を vector で返す */
vector<Double> AdvModelParamSet::GetUpperValues ()
{
    if (modify) { PrepareFit(); }
    vector<Double> v;
    v.clear();

    vector<vector<AdvModelParam*> >::iterator it2;
    it2 = m_fitParams.begin();
    while (it2 != m_fitParams.end()) {
        Double d = (*it2)[0]->GetUpperFitVal();
        v.push_back( d );
        ++it2;
    }
    return v;
}


/** パラメータセットに含まれるパラメータのうち、fit フラグが立っている
    パラメータの値を vector で返す */
vector<Double> AdvModelParamSet::GetLowerValues ()
{
    if (modify) { PrepareFit(); }
    vector<Double> v;
    v.clear();

    vector<vector<AdvModelParam*> >::iterator it2;
    it2 = m_fitParams.begin();
    while (it2 != m_fitParams.end()) {
        Double d = (*it2)[0]->GetLowerFitVal();
        v.push_back( d );
        ++it2;
    }
    return v;
}

