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

AdvModelParam::AdvModelParam() {
    /* initial values */
    m_myname = "";
    m_fit = false;
    limit_upper = false;
    limit_lower = false;
    m_value = 0.0;
    m_upper = DBL_MAX;
    m_lower = -DBL_MAX;
    m_scale = 1.0;
    m_fit_id = 0;
    m_fit_mul = 1.0;
    m_fit_add = 0.0;
}

AdvModelParam::~AdvModelParam() {
}

/** パラメータ値の設定　上限・下限を制限するフラグが立っている場合、
    値を制限する。 */
void AdvModelParam::SetVal(Double v) {
    m_value = v;
    if ( limit_upper && m_value > m_upper ) m_value = m_upper;
    if ( limit_lower && m_value < m_lower ) m_value = m_lower;
}

/** フィッティングルーチンへ現在値を渡す */
Double AdvModelParam::GetFitVal() {
    Double d = m_fit_mul != 0.0 ? m_fit_mul : 1.0 ;
    return (m_value - m_fit_add) / d / m_scale;
}

/** フィッティングルーチンへ上限値を渡す */
Double AdvModelParam::GetUpperFitVal() {
    Double d = m_fit_mul != 0.0 ? m_fit_mul : 1.0 ;
    Double ret;
    if (d > 0.0) {
      ret = (m_upper - m_fit_add) / d / m_scale;
    } else {
      ret = (m_lower - m_fit_add) / d / m_scale;
    }
    return ret;
}

/** フィッティングルーチンへ下限値を渡す */
Double AdvModelParam::GetLowerFitVal() {
    Double d = m_fit_mul != 0.0 ? m_fit_mul : 1.0 ;
    Double ret;
    if (d > 0.0) {
      ret = (m_lower - m_fit_add) / d / m_scale;
    } else {
      ret = (m_upper - m_fit_add) / d / m_scale;
    }
   return ret;
}

/** フィッティングルーチンから値を受け取る */
void AdvModelParam::SetFitVal(Double v) {
    Double d = m_fit_mul != 0.0 ? m_fit_mul : 1.0 ;
    SetVal( v * m_scale * d + m_fit_add );
}

/** パラメータ属性をXMLで設定 */
void AdvModelParam::SetXML ( mxml_node_t *node ) {
    const char* cp;
    Double v;
    Int4   i;

    cp = mxmlElementGetAttr(node, "value");
    if (cp) {
        v = atof(cp);
        SetVal(v);
    }

    cp = mxmlElementGetAttr(node, "fit");
    if (cp) {
        if      (cp[0]=='Y' || cp[0]=='y') SetFitFlag(true);
        else if (cp[0]=='N' || cp[0]=='n') SetFitFlag(false);
        else std::printf("unknown keyword for logical value: %s\n",cp);
    }

    cp = mxmlElementGetAttr(node, "upper_limit");
    if (cp) {
        if      (cp[0]=='Y' || cp[0]=='y') SetLimitUpperFlag(true);
        else if (cp[0]=='N' || cp[0]=='n') SetLimitUpperFlag(false);
        else std::printf("unknown keyword for logical value: %s\n",cp);
    }

    cp = mxmlElementGetAttr(node, "lower_limit");
    if (cp) {
        if      (cp[0]=='Y' || cp[0]=='y') SetLimitLowerFlag(true);
        else if (cp[0]=='N' || cp[0]=='n') SetLimitLowerFlag(false);
        else std::printf("unknown keyword for logical value: %s\n",cp);
    }

    cp = mxmlElementGetAttr(node, "upper_value");
    if (cp) {
        v = atof(cp);
        SetUpperVal(v);
    }

    cp = mxmlElementGetAttr(node, "lower_value");
    if (cp) {
        v = atof(cp);
        SetLowerVal(v);
    }

    cp = mxmlElementGetAttr(node, "fit_id");
    if (cp) {
        i = atoi(cp);
        SetFitID(i);

        cp = mxmlElementGetAttr(node, "fit_scale");
        if (cp) {
            v = atof(cp);
            SetFitMul(v);
        }

        cp = mxmlElementGetAttr(node, "fit_add");
        if (cp) {
            v = atof(cp);
            SetFitAdd(v);
        }
    }
}

/** パラメータ属性をXMLで設定 */
void AdvModelParam::GetXML ( mxml_node_t *node ) {
    char s[250];

    Double v;
    Bool  flag;

    v = GetVal();
    std::snprintf(s,sizeof(s), "%g",v);
    mxmlElementSetAttr(node , "value", s);

    if (GetFitFlag()) {
        flag = true;
        mxmlElementSetAttr(node , "fit", "yes");
    } else {
        flag = false;
        mxmlElementSetAttr(node , "fit", "no");
    }

    if (flag) {
        if (GetLimitUpperFlag()) {
            mxmlElementSetAttr(node , "upper_limit", "yes");
            v = GetUpperVal();
            std::snprintf(s,sizeof(s), "%g",v);
            mxmlElementSetAttr(node , "upper_value", s);
        } else {
            mxmlElementSetAttr(node , "upper_limit", "no");
        }

        if (GetLimitLowerFlag()) {
            mxmlElementSetAttr(node , "lower_limit", "yes");
            v = GetLowerVal();
            std::snprintf(s,sizeof(s), "%g",v);
            mxmlElementSetAttr(node , "lower_value", s);
        } else {
            mxmlElementSetAttr(node , "lower_limit", "no");
        }

        Int4 n;
        n = GetFitID();
        if (n != 0) {
            std::snprintf(s,sizeof(s), "%d",n);
            mxmlElementSetAttr(node , "fit_id", s);

            v = GetFitMul();
            if (v != 1.0) {
                std::snprintf(s,sizeof(s), "%g",v);
                mxmlElementSetAttr(node , "fit_scale", s);
            }

            v = GetFitAdd();
            if (v != 0.0) {
                std::snprintf(s,sizeof(s), "%g",v);
                mxmlElementSetAttr(node , "fit_add", s);
            }
        }
    }
}

