#ifndef PEAK_SEARCH_HH
#define PEAK_SEARCH_HH

#include "Header.hh"
#include "ElementContainer.hh"
#include "AdvDomain.hh"
#include "AdvParamSet.hh"
#include "AdvPeakData.hh"
#include "AdvMessage.hh"
#include "AdvMethod.hh"
#include "AdvMethodType.hh"
#include "AdvOperationBase.hh"

/*!  peak search in 1D */
class AdvPeakSearch : virtual public AdvOperationBase {

    private:
        static const std::string className; // =std::string("myAdvPeakSearch");

    private:
        /*!  peak data: a list of peaks */
        AdvPeakData *peakData; 


    private:

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \retval true if peak condition is sattisfied
         */
        Bool isPeak(std::vector< std::vector<Double> > &trend, const UInt4 pos) const ;

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \retval true if solder condition is sattisfied
         */
        Bool isSholderInIncreaseRegion(std::vector< std::vector<Double> > &trend, const UInt4 pos) const ;

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \retval true if solder condition is sattisfied
         */
        Bool isSholderInDecreaseRegion(std::vector< std::vector<Double> > &trend, const UInt4 pos) const ;

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \raram[in]  h      peak height
         *  \retval true if half-value condition is sattisfied at the pos
         */
        Bool isHalfHeightInIncreaseRegion(std::vector< std::vector<Double> > &trend, const UInt4 pos, const Double h) const ;

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \raram[in]  h      peak height
         *  \retval true if the height at the bottom of a vallery is higher than the half height of the peak
         */
        Bool isHalfHeightInDecreaseRegion(std::vector< std::vector<Double> > &trend, const UInt4 pos, const Double h) const ;

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \raram[in]  h      peak height
         *  \retval true if the height at the sholder is higher than the half height of the peak
         */
        Bool isHigherSholderInIncreaseRegion(std::vector< std::vector<Double> > &trend, const UInt4 pos, const Double h) const ;

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \raram[in]  h      peak height
         *  \retval true if the height at the sholder is higher than the half height of the peak
         */
        Bool isHigherSholderInDecreaseRegion(std::vector< std::vector<Double> > &trend, const UInt4 pos, const Double h) const ;

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \raram[in]  h      peak height
         *  \retval true if the height at the end of histgram is higher than the half height of the peak
         */
        Bool isHigherEndInIncreaseRegion(std::vector< std::vector<Double> > &trend, const UInt4 pos, const Double h) const ;

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \raram[in]  h      peak height
         *  \retval true if the height at the end of histgram is higher than the half height of the peak
         */
        Bool isHigherEndInDecreaseRegion(std::vector< std::vector<Double> > &trend, const UInt4 pos, const Double h) const ;

        /*!
         *  \param[in]  trend  increase-decrease teble
         *  \param[in]  pos    index on the table
         *  \raram[in]  h      peak height
         *  \retval true if the height at the bottom of a valley is higher than the half height of the peak
         */
        Bool isHigherValley(std::vector< std::vector<Double> > &trend, const UInt4 pos, const Double h) const ;

        // seach a half value point for a peak
        Double searchHalfHeightInIncreaseRegion(std::vector< std::vector<Double> > &trend, std::vector<Double> srcX, const UInt4 initPos, const Double h);
        Double searchHalfHeightInDecreaseRegion(std::vector< std::vector<Double> > &trend, std::vector<Double> srcX, const UInt4 initPos, const Double h);

    public:
        /*!  default constructor */
        AdvPeakSearch();

        /*!  constructor */
        AdvPeakSearch(ElementContainer *src);

        /*!  constructor */
#ifndef SWIGPYTHON
        AdvPeakSearch(ElementContainer *src,       AdvMethod     *method   );
#endif
        AdvPeakSearch(ElementContainer *src, const AdvMethodType &methodType);
        AdvPeakSearch(ElementContainer *src, const std::string     &methodName);

        /*!  constructor */
#ifndef SWIGPYTHON
        AdvPeakSearch(ElementContainer *src,       AdvMethod     *method,     const Double xLower, const Double xUpper);
#endif
        AdvPeakSearch(ElementContainer *src, const AdvMethodType &methodType, const Double xLower, const Double xUpper);
        AdvPeakSearch(ElementContainer *src, const std::string     &methodName, const Double xLower, const Double xUpper);

        /*!  constructor */
#ifndef SWIGPYTHON
        AdvPeakSearch(ElementContainer *src,       AdvMethod     *method,     const UInt4  lower,  const UInt4  upper);
#endif
        AdvPeakSearch(ElementContainer *src, const AdvMethodType &methodType, const UInt4  lower,  const UInt4  upper);
        AdvPeakSearch(ElementContainer *src, const std::string     &methodName, const UInt4  lower,  const UInt4  upper);

        /*!  destructor */
        ~AdvPeakSearch();

        /*!  chi square */
        Double chiSq() { return 0.0; };

        /*!  do peak(s) search */
        void execute();

        ///*!  getResult */
        //ElementContainer getResult() { return *(new ElementContainer()); };

        /*!  get a list of peaks */
        AdvPeakData getPeaks() { return *(this->peakData); };

};

#endif
