#ifndef ADVSCATABSOBODYMANAGERMLF
#define ADVSCATABSOBODYMANAGERMLF

//using namespace std;
#include <string>
#include <vector>
#include <gsl/gsl_interp.h>
#include "Header.hh"
//#include "AdvEquipmentManagerDNA.hh"
//#include "AdvPhysicalParameterDNA.hh"
#include "MlfPhysicalConstants.hh"
#include "ElementContainerArray.hh" //[20140414 AS]
#include "ElementContainer.hh" //[20140414 AS]
//using namespace std;
/**
 *  AdvScatAbsoBodyManagerMLF
 *  original code : AdvScatAbsoBodyManagerDNA
 *
 *  @autor Yasuhiro Inamura (J-PARC,MLF)
 *
 *  Change History for moving to Manyo/MLF
 *  2015.10.07 : Change name from ~DNA to ~MLF
 *               Use MlfPhysicalConstans.hh instead of AdvPhysicalParameterDNA
 *  2015.10.06 :
 *     change to virtual function : GetAtomicWeight,SetInfoData,SetSigmaDataNIST
 */

/**
 * enum formType
 *
 * shape of scatterer and/or absorbent
 *
 * @author KOIKE Soh, AdvanceSoft Corp. (original)
 * @author TANIMORI Souichirou, AdvacneSoft Corp.
 * @version 0.0
 * @sice    0.0
 */
enum formType {
    slab,     /**< slab shaped object     */
    cylinder, /**< cylinder shaped object */
    column,   /**< column shaped object   */
    undefined /**< undefined              */
};


/**
 * struct ScatAbsoInfo
 *
 * character of scatterer and/or absorbent is stocked.
 *
 * \author Koike Soh, AdvanceSoft Corp. (original)
 * \author TANIMORI Souichirou, AdvanceSoft Corp. (rewrite comment)
 * \version 0.1
 * \since   0.0
 *
 *  add member function initialise() at \date{2012/02/01}
 */
struct ScatAbsoInfo{
                      // cylinder : entoh, column: enchuu, slab :: heiban
  enum formType form; /**< shape of scatterer and/or absorbent, one of slab, cylinder and column */

                 // rl: large circle, rs: small circle
  Double rl;     /**< the radius of outer circle of a cylinder or a column, in SI unit system [m] */
  Double rs;     /**< the radius of inner circle of a cylinder, 0.0 when column. in SI unit system [m] */
  Double height; /**< height of scatterer and/or absorbent, in SI unit system [m] */
  Double width;  /**< width  of scatterer and/or absorbent, in SI unit system [m] */

  std::vector <std::string> atomname;         /**< atomic names that compose scatterer and/or absorbent */
  std::vector <Double> atomDensityRatio; /**< density ratio of each atom */

  Double ratioT;                /**< Ratio of neutron that enters inner absorbent after it scatters by outer scatterer */
  Double temperature;           /**< temperature */
  Double gasPressure;           /**< pressure of gas */
  Double weightPerVolume;       /**< density of scaterer/absorbent */
  Double effectiveAtomicWeight; /**< atomic weight averaged by constituent atom */
  Double totalDensity;          /**< total density of atoms that compose scatterer and/or absorbent */

  void initialize(); /**< initialize */
};


///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/** Scatterer and Absoannt
 *
 *  @author Koike Soh, AdvanceSoft Corp. (original)
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.1
 *  @since   0.0
 *
 *  \date{2012/02/01}:  erased the member function InitializeStruct(). the function initialize AdvScatAbsoBodyManagerDNA. Intialization of AdvScatAbsoBodyManagerDNA moved to the class.
 */
class AdvScatAbsoBodyManagerMLF{
  protected:

    std::string atomicDataFile; /**< database file where atomic weight and cross section data made by NIST are stocked */
    UInt4 numData;         /**< the number of cross section data for each nuclide or atom. If use NIST data, numData=1. */
    Double** dataCS;       /**< dataCS[i][0] is velocity and dataCS[i][1] is corresponding cross section, where i is data number */

    void DeleteXsDataObject(void);  /**< delete dataCS */

    Double epsilon;      /** threshold value used for judgement of convergence of numerical integral */
    Double epsilonRatio; /** threshold value used for judgement of convergence of numerical integral */
    Double threZero;     /** supplementary threshold value used for judgement of convergence of numerical integral */

    void SetQForSigmaCoefficient(Double); // [20140410 AS]
    void SetAtomicDataFile(std::string);  //[20140410 AS]
    virtual Double GetAtomicWeight(std::string); /**< get atomic weight for the specified nuclide or elemnent */
    Double cohCSF; // coefficient of coherent scattering cross section [20140410 AS]
    Double incCSF; // coefficient of incoherent scattering cross section [20140410 AS]
    Double absCSF; // coefficient of absorption cross section [20140410 AS]
    Bool SigmaCoefficientIsReady();     // [20140410 AS]
  private:
    UInt4 atomicDataFileType;  /**< 0: cross section is calculated by use of NIST data. 1: cross section is calculated by user prepared file.*/

    std::string filepath;                /**< filename of data for cell and sample */
    std::vector<Double> cohCSF_Qx; // Q-x dependent coefficient of coherent scattering cross section [20140410 AS]
    std::vector<Double> cohCSF_Qy; // Q-y dependent coefficient of coherent scattering cross section [20140410 AS]

    Double LinearInterpolation(std::vector<Double>,std::vector<Double>,Double);     // [20140410 AS]

    //Bool SigmaCoefficientIsReady();     // [20140410 AS]
    bool SearchDataBase(); //[Inamura:20170606]
  public:
    AdvScatAbsoBodyManagerMLF(void);
    AdvScatAbsoBodyManagerMLF(std::string);


//    AdvScatAbsoBodyManagerDNA(Char*, Char*);

    /**
     * A destructor
     *
     * do nothing
     */
    virtual ~AdvScatAbsoBodyManagerMLF(void){
    };

    /**
     * get measured value of scattering/absorption cross section of the specified nuclide or atom
     *
     * @param[in] atomname atomic name
     * @param[in] state    'a': absorption, 's': scattering, 't': total
     * @param[in] velocity incident neutron velocity
     * @retval cross section for specified atom
     */
    double GetAtomSigmaFromVelocityRule(std::string atomname, Char state, double velocity);

    /** get the cross cection data
     *
     * @param[in]  *wInfo   pointer for struct variable wallInfo
     * @param[in]  *bInfo   pointer for struct variable bodyInfo
     * @param[in]  energy   incident energy of neutron
     * @param[out] *sigmaBA absorption cross section for body
     * @param[out] *sigmaWA absorption cross section for wall
     * @param[out] *sigmaWS scattering cross section for wall
     */
    void GetSigmaFromVelocityRule(struct ScatAbsoInfo*, struct ScatAbsoInfo*, double, double*, double*, double*);

    /**
     * return cross section data obtained by velocity rule.
     *
     * @param *info   pointer for struct variable AdvScatAbsoBodyManagerDNA
     * @param energy  neutron energy
     * @param state   'a' (absorption), 's' (scattering), t: total
     * @retval cross section for wall or body
     */
    Double ReturnSigmaFromVelocityRule(struct ScatAbsoInfo*, Double, Char);

    /**
     * set AdvScatAbsoBodyManagerDNA variables to values from specified file.
     *
     * @param[in] filename scatterer and/or absorbent data file
     * @param[out] wallInfo information of wall of container
     * @param[out] bodyInfo information of scatterer and/or absorbent
     */
    virtual void SetInfoData(std::string filename, struct ScatAbsoInfo* wallInfo, struct ScatAbsoInfo* bodyInfo);

    /** set an array to cross section data from the file recorded NIST data.
     *
     * @param[in] velocity
     * @param[in] atomname atomic name
     * @param[in] typeCS   type of scattering and absorption data.
     *                     - available values of typeCS
     *                         - 't' sum of scattering cross section and absorption cross sction midefied using user specified velocity
     *                         - 'a' absorption cross sction midefied using user specified velocity
     *                         - 's' scattering cross section
     *                         - 'c' cohrent length
     *                         - 'i' incoherent length
     *
     *  array dataCS[][] in the class keeps NIST data in following way,
     *    - dataCS[0][0]  incident neutron velocity at measurement
     *    - dataCS[0][1]  user specified data using character symbol
     */
    virtual void SetSigmaDataNIST(Double velocity, std::string atomname, std::string typeCS);

    /**
     * return threshold value used for judgement of convergence in numerial integral
     *
     * @return epsilon
     */
    Double GetIntegThresholdValue(void) {return epsilon;};

    /**
     * return threshold value of ratio used for judgement of convergence in numerial integral
     *
     * @return epsilonRatio
     */
    Double GetIntegThresholdRatio(void) {return epsilonRatio;};

    /**
     * set threshold value used for judgement of convergence in numerial integral
     *
     * @set epsilon
     */
    void SetIntegThresholdValue(Double a) {epsilon=a;};

    /**
     * set threshold value Ratio used for judgement of convergence in numerial integral
     *
     * @set epsilonRatio
     */
    void SetIntegThresholdRatio(Double a) {epsilonRatio=a;};

    void SetSigmaCoefficient(Double, Double, Double);                // [20140410 AS]
    void SetSigmaCoefficient(ElementContainerArray, Double, Double); // [20140410 AS]

    Double GetCohCSF();              // [20140410 AS]
    Double GetIncCSF();              // [20140410 AS]
    Double GetAbsCSF();              // [20140410 AS]

    Double GetQDepCohCSF(Double);    // [20140410 AS]
    std::vector<Double> GetQDepCohCSF();  // [20140410 AS]
    std::vector<Double> GetQDepCohCSFq(); // [20140410 AS]
    bool SetDataBaseFile(std::string filepath);
    bool isFoundAtomicDataFile();
    bool isReady();
};

#endif
