#include "AdvLevmarImmutables.hh"

const string AdvLevmarImmutables::className=string("AdvLevmarImmutables");

/**
 *  default constructor
 */
AdvLevmarImmutables::AdvLevmarImmutables() {
}

/**
 *  constructor
 */
AdvLevmarImmutables::AdvLevmarImmutables(ElementContainer &src, AdvDomain &domain, AdvParamSet &param) {
}

/**
 *  constructor
 */
AdvLevmarImmutables::AdvLevmarImmutables(ElementContainerArray &src, vector<AdvDomain> &domainArray, AdvParamSet &param) {
}

#define DeleteArray(array)  if ((array) != NULL)  { delete[] (array); (array) =NULL; }
#define DeleteVector(vector) if ((vector) != NULL) { (vector)->clear(); delete (vector);  (vector)=NULL; }
/**
 *  destructor
 */
AdvLevmarImmutables::~AdvLevmarImmutables() {
}

//Checker
/**
 *  check immutable parametes for Levmar fitting, controls and args
 *
 *  \param[in] src    an element container as the source data
 *  \param[in] domain the domain for fitting
 *  \param[in] param  parameter container for fitting
 */
Bool AdvLevmarImmutables::checkParam(ElementContainer &src, AdvDomain &domain, AdvParamSet &param) {
    string memberName = string("checkParam(ElementContainer &, Domain &, ParamSet &)");
    DebugMessage(className, memberName, "enter\n");

    Bool retval=true;
    retval = retval && this->control.checkParam(param);
    retval = retval && this->args.checkParam(src, domain, param, this->control);

    DebugMessage(className, memberName, "exit\n");
    return retval;
}


Bool AdvLevmarImmutables::checkParam(ElementContainerArray &src, vector<AdvDomain> &domainArray, AdvParamSet &param) {
    string memberName = string("checkParam(ElementContainerArray &, vector<Domain> &, ParamSet &)");
    DebugMessage(className, memberName, "enter\n");

    Bool retval=true;
    retval = retval && this->control.checkParam(param);
    retval = retval && this->args.checkParam(src, domainArray, param, this->control);

    DebugMessage(className, memberName, "exit\n");
    return retval;
}

//Getter
void AdvLevmarImmutables::toInnerForm(ElementContainer &src, AdvDomain &domain, AdvParamSet &param) {
    string memberName=string("toInnerForm(ElementContainer &, Domain &, ParamSet &)");
    DebugMessage(className, memberName, "enter\n");

    this->control.toInnerForm(param);
    this->args.toInnerForm(src, domain, param, this->control);

    DebugMessage(className, memberName, "exit\n");
}

void AdvLevmarImmutables::toInnerForm(ElementContainerArray &src, vector<AdvDomain> &domainArray, AdvParamSet &param) {
    string memberName=string("toInnerForm(ElementContainer &, vector<Domain> &, ParamSet &)");
    DebugMessage(className, memberName, "enter\n");

    this->control.toInnerForm(param);
    this->args.toInnerForm(src, domainArray, param, this->control);

    DebugMessage(className, memberName, "exit\n");
}

//Output

#define Title(str)          message(titleFmt,       str)
#define SubTitle(str)       message(subTitleFmt,    " ", str)
#define SubSubTitle(str)    message(subSubTitleFmt, " ", " ", str)

/**
 *  output immutables parameters for Levmar to the standard output
 */
void AdvLevmarImmutables::output() {
    string memberName=string("output()");
    DebugMessage(className, memberName, "enter\n");

    char titleFmt[]      ="%s\n";
    char subTitleFmt[]   ="%4s%s\n";
    char subSubTitleFmt[]="%4s%4s%s\n";

    Title("Initital stat for Fitting by Levenberg-Marquardt");

    SubTitle("Control Parametes");
    this->control.output();

    if (this->control.constrain != AdvLevmarConsts::NO_CONSTRAIN) {
        SubTitle("Constrain");
        switch (this->control.constrain) {
            case AdvLevmarConsts::BOX:
#ifdef HAVE_LAPACK
            case AdvLevmarConsts::BLEC:
            case AdvLevmarConsts::BLIC:
            case AdvLevmarConsts::BLEIC:
#endif // HAVE_LAPACK
                //SubSubTitle("box");
                SubSubTitle( AdvLevmarConsts::CONSTRAIN_STR[AdvLevmarConsts::BOX].c_str() );
                this->args.outputConstrainBox(this->control.constrain);
                break;
            default:
                break;
        }
        message("\n");

#ifdef HAVE_LAPACK
        switch (this->control.constrain) {
            case AdvLevmarConsts::LEC:
            case AdvLevmarConsts::BLEC:
            case AdvLevmarConsts::LEIC:
            case AdvLevmarConsts::BLEIC:
                //SubSubTitle("equations");
                SubSubTitle(AdvLevmarConsts::CONSTRAIN_STR[AdvLevmarConsts::LEC].c_str());
                this->args.outputConstrainExpressions(this->args.nEq, this->args.nParam, this->args.A, this->args.b);
                break;
            default:
                break;
        }
        message("\n");

        switch (this->control.constrain) {
            case AdvLevmarConsts::LIC:
            case AdvLevmarConsts::BLIC:
            case AdvLevmarConsts::LEIC:
            case AdvLevmarConsts::BLEIC:
                //SubSubTitle("equations");
                SubSubTitle(AdvLevmarConsts::CONSTRAIN_STR[AdvLevmarConsts::LIC].c_str());
                this->args.outputConstrainExpressions(this->args.nIneq, this->args.nParam, this->args.C, this->args.d);
                break;
            default:
                break;
        }

#endif // HAVE_LAPACK
    }

    SubTitle("Fitting Functions and Initial Values of their Parametes");
    this->args.outputInitialFittingParam();

    SubTitle("Other Options");
    this->args.outputOptions(this->control);

    SubTitle("Source Data");
    this->args.outputAdditionalData();
    //this->args.outputReferenceData();

    DebugMessage(className, memberName, "exit\n");
}
