#ifndef SMALLANGLE_H
#define SMALLANGLE_H

#include "Header.hh"
#include <gsl/gsl_complex.h>
#include "AdvModel.hh"
#include "AdvFuncBase.hh"
#include "AdvParamSet.hh"
#include "ElementContainer.hh"

#include "AdvModelParticleType.hh"

#ifndef LIBMXML4
#include <mxml.h>
#else
#include <libmxml4/mxml.h>
#define MXML_DESCEND MXML_DESCEND_ALL
#endif

class AdvModelParticle;
class AdvModelLattice;
class AdvModelParam;

/**
 *  small angle reflection
 */
class AdvModelSmallAngle : public AdvModel, public AdvFuncBase, public AdvModelParticleType
{
    public:
        /** default constructor */
        AdvModelSmallAngle() ;

        /** destructor */
        ~AdvModelSmallAngle() ;

#ifdef USE_POINTER
        /** evaluate the value of the function */
        Double eval(const Double x, const Double *p) ;
#ifdef HAVE_DIFFERENTIAL_MEMBER
        /** evaluate the value of the 1st derivative function */
        Double der1st(const Double x, const Double *p) ;
        /** evaluate the value of the 2nd derivative function */
        Double der2nd(const Double x, const Double *p) ;
        /** evaluate the gradient of the function for parameters */
        Double *gradient(const Double x, const Double *p);
#endif //HAVE_DIFFERENTIAL_MEMBER
#endif //USE_POINTER

#ifdef USE_VECTOR
        /** evaluate the value of the function */
        Double eval(const Double x, const std::vector<Double> &p);
#ifdef HAVE_DIFFERENTIAL_MEMBER
        /** evaluate the value of the 1st derivative function */
        Double der1st(const Double x, const std::vector<Double> &p);
        /** evaluate the value of the 2nd derivative function */
        Double der2nd(const Double x, const std::vector<Double> &p);
        /** evaluate the gradient of the function for parameters */
        std::vector<Double> gradient(const Double x, const std::vector<Double> &p);
#endif //HAVE_DIFFERENTIAL_MEMBER
#endif //USE_VECTOR

        void SetFitParam (const Double* p);


        /** 関数パラメータの設定 */
        void SetFuncParam ( const char* fname );

        /** 現在の関数パラメータの取得 */
        void GetFuncParam ( const char* fname );

        /** 散乱強度計算 */
//        Double         CalcIq ( const Double Q );
        // std::vector<Double> CalcIq ( const Double Q, Int4 flag );

//        void CalcIq ( ElementContainer& ein, ElementContainer& eout );
//        void CalcIq ( ElementContainer& , ElementContainer& , ElementContainer& );
//        void CalcIq ( ElementContainer& , ElementContainer& , ElementContainer& , ElementContainer& );

        std::vector<Double> GetParamVals();
        std::vector<Double> GetUpperVals();
        std::vector<Double> GetLowerVals();

        enum Function {
           USE_PARTICLE  = 0,
           POWER_LAW     = 1,
           DEBYE_CHAIN   = 2,
           GAUSSIAN_COIL = 3,
           GIUNIER_LAW   = 4,
        };

        enum InterParticleType {
           NONE          = 0,
           TWO_BODY      = 1,
           LATTICE       = 2,
        };

    private:
        /**  測定データの縦軸のスケール因子 */
        AdvModelParam*  efactor;

        /**  バックグラウンドノイズ Q依存性のない一定値 */
        AdvModelParam*  bkg;

        std::vector< AdvModelParticle* > particles;
        //AdvModelLattice*  lattice;

        Function           ifunc;
        InterParticleType  istruct;
};

#endif
