#ifndef SEARCHINHEADER
#define SEARCHINHEADER

/* Header.hh should be included on the top to avoid environments
 * specific issues (see Header.hh for the detail).
 */
#include "Header.hh"

#include <string>
#include "ElementContainer.hh"
#include "ElementContainerArray.hh"
#include "ElementContainerMatrix.hh"
#include "HeaderBase.hh"
#include "StringTools.hh"
#ifdef MULTH
    #include <omp.h>
#endif

//////////////////////////////////
// SearchInHeader
/////////////////////////////////

//! Find function in Header
/*!
 * This function allows users to find ElementContainer(s) or ElementContainerArray(s)
 * which include given "Key" and values in the Header information
 *
 * Example:
 * @code
 *     SIH = Manyo.SearchInHeader()
 *     SIH.SetTarget( dat )         # set ElementContainerMatrix or ElementContainerArray
 *     SIH.Search( "PIXELID", 3 )   # serch PIXELID=3
 *     res_vect = SIH.PutResults()  # return std::vector< std::vector<UInt4> >, std::vector<UInt4> include [ index of ECM, index of ECA ]
 *                                  # ec = dat( ret_vect[0][0], ret_vect[0][1] ) to get first result container.
 * @endcode
 * or simply one
 * @code
 *     res_eca = SIH.PutResultAsArray()  # return ElementContainerArray including required ElementContainers
 * @endcode
 *
 */
class SearchInHeader
{
private:

    std::string CommentHead;     /* Header of output comments */
    void Initialize(bool flag=false);
        //!< Initialization
        /*!<
         *   @param flag Debug flag. 1 for showing debug messages, 0(default) for not
         */
    std::vector< std::vector<UInt4> > _ResultIndex;
    bool isSearchArray;
    bool isDebug;

protected:
    ElementContainerMatrix *_TargetECM;
    ElementContainerArray *_TargetECA;
    std::vector<UInt4> _Search( ElementContainerArray *eca, std::string index, Int4 val );
    std::vector<UInt4> _Search( ElementContainerArray *eca, std::string index, Int4 val_lower, Int4 val_upper );
    std::vector<UInt4> _Search( ElementContainerArray *eca, std::string index, double val_lower, double val_upper );
    std::vector<UInt4> _Search( ElementContainerArray *eca, std::string index, std::string val, bool isStrict=false );

public:
    SearchInHeader(bool flag=false);
        //!< Constructor
        /*!<
         *   @param flag (bool):Debug flag. true for showing debug messages, false (default) for not
         */
    SearchInHeader(ElementContainerMatrix *target);
        //!< Constructor
        /*!<
         *   @param target (ElementContainerMatrix): Target data
         */
    SearchInHeader(ElementContainerArray *target);
        //!< Constructor
        /*!<
         *   @param target (ElementContainerArray): Target data
         */
    ~SearchInHeader();
        //!< Destructor
        /*!<
         */
    void SetTarget( ElementContainerMatrix *target );
        //!< Set target ElementContainerMatrix
        /*!<
         * Search command search in the target container. The target can be set ElementContainerMatrix
         *   SetTarget( ElementContainerMatrix *target );
         *
         * @param target (ElementContainerMatrix* ): Target data
         */
    void SetTarget( ElementContainerArray *target );
        //!< Set target ElementContainerArray
        /*!<
         * Search command search in the target container. The target can be set ElementContainerArray
         *   SetTarget( ElementContainerArray *target );
         *
         * @param target (ElementContainerArray* ): Target data
         */
    bool Search( std::string key, Int4 val );
        //!< Search ElementContainer by given Int4 value with key
        /*!<
         *   Search( std::string key, Int4 val );
         *
         * @param key (std::string): Key in Header for searching
         * @param val (Int4): value for searching
         * @retval true    no trouble
         * @retval false   trouble happens
         */
    bool Search( std::string key, Int4 val_lower, Int4 val_upper );
        //!< Search ElementContainer by given Int4 value range with key
        /*!<
         *   Search( std::string key, Int4 val_lower, Int4 val_upper );
         *
         * @param key (std::string): Key in Header for searching
         * @param val_lower (Int4): lower limit value for searching
         * @param val_upper (Int4): upper limit value for searching
         * @retval true    no trouble
         * @retval false   trouble happens
         */
    bool Search( std::string key, double val_lower, double val_upper );
        //!< Search ElementContainer by given Double value range with key
        /*!<
         *   Search( std::string key, double val_lower, double val_upper );
         *
         * @param key (std::string):  Key in Header for searching
         * @param val_lower (Double): lower limit value for searching
         * @param val_upper (Double):  upper limit value for searching
         * @retval true    no trouble
         * @retval false   trouble happens
         */
    bool Search( std::string key, std::string val, bool isStrict=false );
        //!< Search ElementContainer by given std::string with key
        /*!<
         *   Search( std::string key, std::string val, bool isStrict );
         *
         * @param key (std::string): Key in Header for searching
         * @param val (std::string): value for searching
         * @param isStrict (bool): false means value in Header include given value, true means value in Header is equal strictly.
         * @retval true    no trouble
         * @retval false   trouble happens
         */
    bool SearchArray( std::string key, Int4 val );
        //!< Search ElementContainerArray by given Int4 value with key
        /*!<
         *   SearchArray( std::string key, Int4 val );
         *
         * @param key (std::string): Key in Header for searching
         * @param val (Int4): value for searching
         * @retval true    no trouble
         * @retval false   trouble happens
         */
    bool SearchArray( std::string key, Int4 val_lower, Int4 val_upper );
        //!< Search ElementContainerArray by given Int4 value range with key
        /*!<
         *   SearchArray( std::string key, Int4 val_lower, Int4 val_upper );
         *
         * @param key (std::string): Key in Header for searching
         * @param val_lower (Int4): lower limit value for searching
         * @param val_upper (Int4): upper limit value for searching
         * @retval true    no trouble
         * @retval false   trouble happens
         */
    bool SearchArray( std::string key, Double val_lower, Double val_upper );
        //!< Search ElementContainerArray by given Double value range with key
        /*!<
         *   SearchArray( std::string key, double val_lower, double val_upper );
         *
         * @param key (std::string)  Key in Header for searching
         * @param val_lower (Double): lower limit value for searching
         * @param val_upper (Double):  upper limit value for searching
         * @retval true    no trouble
         * @retval false   trouble happens
         */
    bool SearchArray( std::string key, std::string str_val, bool isStrict=false );
        //!< Search ElementContainerArray by given
        /*!<
         *   SearchArray( std::string key, std::string str_val, bool isStrict );
         *
         * @param key (std::string): Key in Header for searching
         * @param val (std::string): value for searching
         * @param isStrict (bool): false means value in Header include given value, true means value in Header is equal strictly.
         * @retval true    no trouble
         * @retval false   trouble happens
         */
    ElementContainerArray PutResultAsArray();
        //!< Return current results of Search method
        /*!<
         *   Return current results of Search method as ElementContainerArray
         *
         * @return ElementContainerArray
         */
    ElementContainerMatrix PutResultSearchArray();
        //!< Return current results of SearchArray method
        /*!<
         *   Return current results of Search method as ElementContainermatrix
         *
         * @return ElementContainerMatrix
         */
    std::vector< std::vector<UInt4> > PutResults(){ return _ResultIndex; }
        //!< Return current results
        /*!<
         *   Return current results as index
         *
         * @return _ResultIndex
         */
    std::vector< UInt4 > PutResultIndex( UInt4 index=0 );
        //!< Return current results
        /*!<
         *   Return current results of ElementContainerArray index in given ElementContainerMatrix
         *   or ElementContainer index in ElementContainerArray
         *
         * @param index (UInt4): if index=0, return ElementContainerArray index. index=1 ElementContainer index
         * @return (std::vector<UInt4>) index of ElementContainerArray or ElementContainer
         */
    void ShowResults();
        //!< Show set of psd and pixel index for current results
        /*!<
         */
    void ChangeDebugFlag( bool flag );
        //!< Change Debug flag
        /*!<
         * @param  flag (bool):  Debug flug. true for showing debug messages. false(default) for not.
         */
    std::vector<Double> FindLimitElementDoubleVector( std::string key, UInt4 index );
        //!< Find limit of values in double std::vector element with given key and index
        /*!<
         * @param  key (std::string): Index Key in Header for searching
         * @param  index (UInt4): index number of target element in given std::vector
         */
};

#endif
