#ifndef MODELPARAM_HH
#define	MODELPARAM_HH

#include "Header.hh"
#include "AdvModel.hh"

#include <mxml.h>

class AdvModelParam {

public:
    AdvModelParam();
    virtual ~AdvModelParam();
    /** パラメータ名 */
    void SetName (string name) { m_myname = name; }
    string GetName ()          { return m_myname; }

    /**  最適化を行うかどうかのフラグ */
    void SetFitFlag(Bool flag) { m_fit = flag; }
    Bool GetFitFlag()          { return m_fit; }

    /**  上限を設定するかどうかのフラグ */
    void SetLimitUpperFlag(Bool flag) { limit_upper = flag; }
    Bool GetLimitUpperFlag()          { return limit_upper; }

    /**  下限を設定するかどうかのフラグ */
    void SetLimitLowerFlag(Bool flag) { limit_lower = flag; }
    Bool GetLimitLowerFlag()          { return limit_lower; }

    /**  上限値 
     *     UpperFlag が立っている場合、上限値を上まわらないように
     *     制限する。
     */
    void   SetUpperVal(Double v) { m_upper = v; }
    Double GetUpperVal()         { return m_upper; }

    /**  下限値
     *     LowerFlag が立っている場合、下限値を下まわらないように
     *     制限する。
     */
    void   SetLowerVal(Double v) { m_lower = v; }
    Double GetLowerVal()         { return m_lower; }

    /**  パラメータの現在値 */
    void   SetVal(Double v);
    Double GetVal()              { return m_value; }

    /**  パラメータのスケール
     *     フィッティングルーチンでは、
     *     数値微分を行うときの微小変位や
     *     simulated annealing のランダム変位に
     *     全パラメータ共通の値を用いる。
     *     そのため、パラメータ値のオーダー(桁数)を
     *     できるだけ揃えたい。
     *     fit_scale に基本的なパラメータ値を設定すると、
     *     次の変換を行う。
     *
     *       (初期値)
     *         モデル関数 --> m_scale で割る   --> フィッティングルーチン
     *
     *       (フィッティング中)
     *         モデル関数 <-- m_scale を掛ける <-- フィッティングルーチン
     *
     */
    void   SetScale(Double v)   { m_scale = v; }
    Double GetScale()           { return m_scale; }

    /**  複数のパラメータを連動させたい場合
     *     パラメータに番号(ただし 0 以外)をつける（FitID)
     *     FitID が同じ番号のパラメータは連動する。
     *     連動させたくない場合は、FitID を 0 にする(←デフォルト値)
     *     あるいは、FitID が他のパラメータと被らないように注意する。
     *
     *     FitIDが同じ番号のパラメータは、フィッテングルーチンでは
     *     一つのパラメータに束ねられる。
     *     フィッティングルーチンへ渡す初期値はどれか一つのモデルパラメータ
     *     から決める。(他の同一FitIDパラメータの初期値は無視)
     *
     *     フィッティングルーチンからモデル関数パラメータに戻す際に
     *     m_scale を掛けるのに加えて、各パラメータごとに与えられた
     *     fit_scale を掛けて、fit_add を加える。
     *
     *     パラメータA, B を B = p A + q の条件で連動させるためには、
     *     パラメータA の fit_scale = 1, fit_add = 0
     *     パラメータB の fit_scale = p, fit_add = q
     *     とすればよい。(m_scale が同一の場合)
     *       (m_scaleが異なる場合は非対応)
     *
     */
    void   SetFitID(Int4 n)     { m_fit_id = n; }
    Int4   GetFitID()           { return m_fit_id; }

    void   SetFitMul(Double v)  { m_fit_mul = v; }
    Double GetFitMul()          { return m_fit_mul; }

    void   SetFitAdd(Double v)  { m_fit_add = v; }
    Double GetFitAdd()          { return m_fit_add; }

    /**
     *     フィッティングルーチンへ値を渡す
     */
    Double GetFitVal();
    Double GetUpperFitVal();
    Double GetLowerFitVal();

    /**
     *     フィッティングルーチンから値を受け取る
     */
    void   SetFitVal(Double v);

    /**
     *     XML でパラメータ属性を設定/出力
     */
    void SetXML ( mxml_node_t *node );
    void GetXML ( mxml_node_t *node );


private:
    string m_myname;

    Bool m_fit;          //!  フィットするか固定値かのフラグ
    Bool limit_upper;    //!  上限を制限するかのフラグ
    Bool limit_lower;    //!  下限を制限するかのフラグ
    Double m_value;      //!  パラメータの現在値
    Double m_upper;      //!  上限値
    Double m_lower;      //!  下限値

    Double m_scale;      //!  パラメータの大きさの基準

    Int4   m_fit_id;     //!  パラメータ番号
    Double m_fit_mul;
    Double m_fit_add;
};

#endif

