#ifndef BOOSTXMLPARSER
#define BOOSTXMLPARSER

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

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/version.hpp>

#include "Map.hh"
#include "StringTools.hh"

//////////////////////////////////
// BoostXmlParser
/////////////////////////////////

//! Function for read XML file using boost::property_tree
/*! This gives a simple way to access to elements
 *  by using path-to-element text.
 *  Example for path format
 *  @code
 *  <node1>
 *      <node2 i="1">
 *           <node3>Target</node3>
 *      </node2>
 *      <node2 i="2">...</node2>
 *  </node1>
 *  @endcode
 *  When you want to touch "Target",
 *  the path is "node1/node2,i=1/node3"
 *  or use XPath format ( poor functions )
 *  like "node1/node2[@i='1']/node3"
 */

class BoostXmlParser
{
private:
    std::string _MessageTag;
    std::string _CurrentKey;
    std::string _MakeNewKey( std::string path="" );
    StringTools* _st;

protected:
    Map< boost::property_tree::ptree* >* _TreeMap;
    void Initialize();
    boost::property_tree::ptree& _getNode( boost::property_tree::ptree& pIn, std::string path, bool& status, bool makeNew );
        //!< Picks up node indicated by path.
        /*!<
         *   _getNode( boost::property_tree::ptree& pIn, std::string path, bool& status, bool makeNew )
         *   @param pIn      (ptree)  ptree of node
         *   @param path     (std::string) path to element to be removed
         *   @param status   (bool)   status will be set in this method
         *   @param makeNew  (bool)   whether make new node or not when no node indicated by given path
         *   @return ptree
         */
    bool _eraseNode( boost::property_tree::ptree& pIn, std::string path, std::string attr="" );
        //!< erases node or attribute directed by given path
        /*!<
         *   _eraseNode( boost::property_tree::ptree& pIn, std::string path, std::string attr="" )
         *   @param pIn    (ptree)  ptree of node
         *   @param path   (std::string) path to element to be removed
         *   @param attr   (std::string) attribute name if you want to delete an attribute
         *   @retval true  :succeeded
         *   @retval false :failed
         */
    std::string _trimPath( std::string path );
        //!< Trims given path
        /*!<
         *   1) removes spaces, 2) converts XPath format to our one,
         *   3) trimes slash at head and tail of path.
         *   _trimPath( std::string path )
         *   @param path  (std::string) path
         *   @reurn trimed std::string
         */
    bool _isQuietMode; // no message when xml path is not found.
    bool _isLoadXmlString;
    bool _isDebugMode;

public:
    BoostXmlParser();
        //!< Constructor
        /*!<
         */
    BoostXmlParser( std::string xmlfile );
        //!< Constructor
        /*!<
         *    BoostXmlParser( sting xmlfile )
         *
         *    @param xmlfile (std::string) path to xml file
         */
    BoostXmlParser( std::string key, std::string xmlfile );
        //!< Constructor
        /*!<
         *    BoostXmlParser( std::string key, std::string xmlfile )
         *
         *    @param key     (std::string) Key for xml info
         *    @param xmlfile (std::string) path to xml file
         */
    ~BoostXmlParser();
        //!< Destructor
        /*!<
         */
    bool CreateNewTree( std::string key="" );
        //!< Creates new property tree indexed by key.
        /*!<
         *   CreateNewTree( [std::string key] )
         *
         *   @param key (std::string) key for xml info
         *   @retval true   succeeded
         *   @retval false  failed
         */
    bool AddElement( std::string path, std::string cont );
    bool AddElement( std::string key, std::string path, std::string cont );
    bool AddElement( std::string path, std::vector<std::string> attr_v, std::vector<std::string> val_v);
    bool AddElement( std::string key, std::string path, std::vector<std::string> attr_v, std::vector<std::string> val_v);
        //!< Adds elements and attributes to a tree
        /*!<
         *   AddToTree( [std::string key,] std::string path, std::string cont );
         *   AddToTree( [std::string key,] std::string path, std::vector<std::string> attr_v, std::vector<std::string> val_v );
         *
         *   @param key   (std::string) key for xml info
         *   @param path  (std::string) path to elements and attributes to be added
         *   @param cont  (std::string) contents to be added
         *   @param att_v (std::vector<std::string>) attribute names list
         *   @param val_v (std::vector<std::string>) attribute values list
         *   @retval true  succeeded
         *   @retval false failed
         */
    bool RemoveElement( std::string path, std::string attr );
    bool RemoveElement( std::string key, std::string path, std::string attr );
        //!< Removes elements or attribute
        /*!<
         *   RemoveTree( std::string key, std::string path, std::string attr )
         *
         *   @param key  (std::string) key for xml info
         *   @param path (std::string) path to element including attribute to be removed
         *   @param attr (std::string) attribute name. if empty, delete tree of given path
         *   @retval true  succeeded
         *   @retval false failed
         */
    bool Save( std::string path );
    bool Save( std::string key, std::string path );
        //!< Saves tree to xml file.
        /*!<
         *   Save( std::string key, std::string path )
         *
         *   @param key  (std::string) key for xml info
         *   @param path (std::string) path to file
         *   @retval true  succeeded
         *   @retval false failed
         */
    bool Load( std::string arg );
        //!< Load tree from xml file.
        /*!<
         *   Load( std::string key )
         *
         *   @param key  (std::string) key for xml info
         *   @retval true  succeeded
         *   @retval false failed
         */
    bool Load( std::string key, std::string arg );
        //!< Load tree from xml file.
        /*!<
         *   Load( std::string key, std::string path )
         *
         *   @param key  (std::string) key for xml info
         *   @param arg (std::string) path/to/file or xml std::string
         *   @retval true  succeeded
         *   @retval false failed
         */
    bool LoadFromString( std::string xmlstring );
        //!< Load tree from std::string including xml.
        /*!<
         *   LoadFromString( std::string xmlstring )
         *
         *   @param key  (std::string) key for xml info
         *   @retval true  succeeded
         *   @retval false failed
         */
    bool LoadFromString( std::string key, std::string xmlstring );
        //!< Load tree from std::string including xml.
        /*!<
         *   LoadFromString( std::string key, std::string xmlstring )
         *
         *   @param key  (std::string) key for xml info
         *   @param path (std::string) std::string of xml description
         *   @retval true  succeeded
         *   @retval false failed
         */
    bool isLoadXmlString(){ return _isLoadXmlString; }
        //!< Checks whether XML information is given as std::string or not (file)
        /*!<
         *   isLoadXmlString()
         *
         *   @retval true  XML information is given as std::string
         *   @retval false XML information is given by XML file reading
         */
    std::string OutToString( std::string key, std::string path, bool withIndent );
        //!< Output element tree included by given element path as std::string of xml.
        /*!<
         *   OutToString( std::string key, std::string path, bool withIndent )
         *
         *   @param key  (std::string) key for xml info
         *   @param path (std::string) path to xml element
         *   @param withIndent (bool) whether output std::string is formatted by indent
         *   @return xml std::strings
         */
    std::string OutToString( std::string path, bool withIndent );
        //!< Output element tree included by given element path as std::string of xml.
        /*!<
         *   OutToString( std::string path, bool withIndent )
         *
         *   @param path (std::string) path to xml element
         *   @param withIndent (bool) whether output std::string is formatted by indent
         *   @return xml std::strings
         */
    std::string OutToString( bool withIndent );
        //!< Output element tree included by given element path as std::string of xml.
        /*!<
         *   OutToString( bool withIndent )
         *
         *   @param withIndent (bool) whether output std::string is formatted by indent
         *   @return xml std::strings
         */
    std::string OutAllToString( std::string key, bool withIndent=false ){ return OutToString( key, "", withIndent ); }
        //!< Output all element tree as std::string of xml.
        /*!<
         *   OutAllToString( std::string key, bool withIndent=false )
         *
         *   @param key  (std::string) key for xml info
         *   @param withIndent (bool) whether output std::string is formatted by indent
         *   @return xml std::strings
         */
    std::string OutAllToString( bool withIndent=false ){ return OutToString( "", withIndent ); }
        //!< Output all element tree as std::string of xml.
        /*!<
         *   OutAllToString( bool withIndent=false )
         *
         *   @param withIndent (bool) whether output std::string is formatted by indent
         *   @return xml std::strings
         */

    std::string PutContent( std::string path );
    std::string PutContent( std::string path, std::string attr);
    std::string PutContent( std::string key, std::string path, std::string attr);
    std::string putTextContent( std::string key, std::string path, std::string attr="");
        //!< Puts contents or attribute directed by a given path
        /*!< putTextContent is used for old code to use MiniXmlReader
         *   PutContent( [std::string key,] std::string path, std::string attr )
         *
         *   @param key  (std::string) key for xml info
         *   @param path (std::string) path to element
         *   @param attr (std::string) attribute name you want to get
         *   @return std::string value
         */
    std::string PutContent( boost::property_tree::ptree* curNode, std::string path, std::string attr );
        //!< Puts contents or attribute directed by a given path under current node
        /*!<
         *   PutContent( boost::property_tree::ptree* curNode, std::string path, std::string attr )
         *
         *   @param curNode (boost::property_tree::ptree) current node
         *   @param path (std::string) path to element
         *   @param attr (std::string) attribute name you want to get
         *   @return std::string value
         */
    std::vector<std::string> PutAttValList( std::string path, std::string attr );
    std::vector<std::string> PutAttValList( std::string key, std::string path, std::string attr );
        //!< Puts all attribute-values included in a given path
        /*!<
         *   PutAttValList( [std::string key,] std::string path, std::string attr )
         *
         *   @param key  (std::string) key for xml info
         *   @param path (std::string) path to element
         *   @param attr (std::string) attribute name you want to get
         *   @return (std::vector<std::string>) list of found attributes
         */
    std::vector<std::string> PutAttValList( boost::property_tree::ptree* curNode, std::string path, std::string attr );
        //!< Puts all attribute-values included in a given path under current node
        /*!<
         *   PutAttValList( boost::property_tree::ptree* curNode, std::string path, std::string attr )
         *
         *   @param curNode (boost::property_tree::ptree) current node
         *   @param path (std::string) path to element
         *   @param attr (std::string) attribute name you want to get
         *   @return (std::vector<std::string>) list of found attributes
         */
    std::vector<std::string> PutElemContList( std::string path, std::string elename );
    std::vector<std::string> PutElemContList( std::string key, std::string path, std::string elename );
        //!< Puts all contents of the element included in a given path
        /*!<
         *   PutAttValList( [std::string key,] std::string path, std::string attr )
         *
         *   @param key  (std::string) key for xml info
         *   @param path (std::string) path to element
         *   @param elename (std::string) included element name you want to get
         *   @return (std::vector<std::string>) list of found contents
         */
    std::vector<std::string> PutElemContList( boost::property_tree::ptree* curNode, std::string path, std::string elename );
        //!< Puts all contents of the element included in a given path
        /*!<
         *   PutElemContList( boost::property_tree::ptree* curNode, std::string path, std::string attr )
         *
         *   @param curNode (boost::property_tree::ptree) current node
         *   @param path (std::string) path to element
         *   @param elename (std::string) included element name you want to get
         *   @return (std::vector<std::string>) list of found contents
         */
    UInt4 PutNumOfElements( std::string path );
    UInt4 PutNumOfElements( std::string key, std::string path );
        //!< Puts the number of elements included in a given path
        /*!<
         *   PutNumOfElements( [std::string key,] std::string path )
         *
         *   @param key  (std::string) key for xml info
         *   @param path (std::string) path to element
         *   @param attr (std::string) attribute name you want to get
         *   @return (UInt4) number of elements
         */
    UInt4 PutNumOfElements( boost::property_tree::ptree* curNode, std::string path );
        //!< Puts the number of elements included in a given path from current node
        /*!<
         *   PutNumOfElements( boost::property_tree::ptree* curNode, std::string path )
         *
         *   @param curNode (boost::property_tree::ptree) current node
         *   @param path (std::string) path to element
         *   @param attr (std::string) attribute name you want to get
         *   @return (UInt4) number of elements
         */
    bool hasPath( std::string path );
    bool hasPath( std::string key, std::string path );
        //!< checks the existence of given path-to-element
        /*!<
         *   bool hasPath( [std::string key,] std::string path )
         *
         *   @param key  (std::string) key name for loaded XML info
         *   @param path (std::string) path-to-element
         *   @retval true   given path exists
         *   @retval false  given path does not exist
         */
    bool hasPath( boost::property_tree::ptree* curNode, std::string path );
        //!< checks the existence of given path-to-element
        /*!<
         *   bool hasPath( boost::property_tree::ptree* curNode, std::string path )
         *
         *   @param curNode (boost::property_tree::ptree) current node
         *   @param path (std::string) path-to-element
         *   @retval true   given path exists
         *   @retval false  given path does not exist
         */
    std::vector<std::string> PutKeys();
        //!< Puts key list
        /*!<
         *   @param None
         *   @return std::string std::vector of key list
         */
    bool hasKey( std::string key );
        //!< Checks whether xml with given key is loaded or not
        /*!<
         *   @param key (std::string) key name
         *   @retval true  loaded xml with given key
         *   @retval false not loaded xml with given key
         */
    UInt4 PutSize();
        //!< Puts the number of added xml info
        /*!<
         *   @param None
         *   @return UInt4 value
         */
    void Clear( std::string key="", bool isForced=false );
        //!< Deletes property tree by a given key
        /*!<
         *   Clear( std::string key="", bool isForced=false )
         *
         *   @param key  (std::string) key for xml info
         *   @param isForced (bool) no warning message if key is not found
         *   @return None
         */
    bool ChangeCurrent( std::string key );
        //!< Changes current tree by a given key
        /*!<
         *   ChangeCurrent( std::string key )
         *
         *   @param key  (std::string) key for xml info
         *   @retval true  : succeeded
         *   @retval false : failed
         */
    std::string PutCurrentKey(){ return _CurrentKey; }
        //!< Puts the key of current tree
        /*!<
         *   PutCurrentKey()
         *
         *   @return key (std::string)
         */
    bool CopyTree( std::string org_key, std::string new_key );
    void SetQuiet( bool isquiet=true ){ _isQuietMode=isquiet; }
    boost::property_tree::ptree* PutNode( std::string path, std::string attr );
        //!< Takes out the node given path and attributes
        /*!<
         *   PutNode( std::string path, std::string attr );
         *
         *   @param path  (std::string) path to elements and attribute you want to get
         *   @param attr  (std::string) attribute name you want to get
         *   @return node (boost::property_tree::ptree)
         */
    boost::property_tree::ptree* PutNode( std::string key, std::string path, std::string attr );
        //!< Takes out the node given path and attributes
        /*!<
         *   PutNode( std::string key, std::string path, std::string attr );
         *
         *   @param key   (std::string) key name for loaded XML info
         *   @param path  (std::string) path to elements and attribute you want to get
         *   @param attr  (std::string) attribute name you want to get
         *   @return node (boost::property_tree::ptree)
         */
    boost::property_tree::ptree* PutNode( boost::property_tree::ptree* curNode, std::string path, std::string attr );
        //!< Takes out the node given path and attributes
        /*!<
         *   PutNode( boost::property_tree::ptree* curNode, std::string path, std::string attr );
         *
         *   @param curNode (boost::property_tree::ptree) current node
         *   @param path    (std::string) path to elements and attribute you want to get under current node
         *   @param attr    (std::string) attribute name you want to get
         *   @return node   (boost::property_tree::ptree)
         */
    std::vector<boost::property_tree::ptree*> PutFoundChildNodes( boost::property_tree::ptree* curNode, std::string path);
        //!< Takes out all nodes found by current node and given path
        /*!<
         *   PutFoundChildNodes( boost::property_tree::ptree* curNode, std::string path);
         *
         *   @param curNode (boost::property_tree::ptree) current node
         *   @param path    (std::string) path to elements and attribute you want to get under current node
         *   @return node   (boost::property_tree::ptree)
         */
    std::vector<std::string> PutChildrenElemNames( std::string path );
        //!< Put list of elements names included in given path
        /*!<
         *   PutChildrenElemNames( std::string path );
         *
         *   @param path    (std::string) path to elements and attribute you want to get under current node
         *   @return std::vector<std::string>  List of names
         */
    std::vector<std::string> PutChildrenElemNames( std::string key, std::string path );
        //!< Put list of elements names included in given path
        /*!<
         *   PutChildrenElemNames( std::string key, std::string path );
         *
         *   @param key   (std::string) key name for loaded XML info
         *   @param path    (std::string) path to elements and attribute you want to get under current node
         *   @return std::vector<std::string>  List of names
         */
    std::vector<std::string> PutChildrenElemNames( boost::property_tree::ptree* curNode, std::string path );
        //!< Put list of elements names included in given path
        /*!<
         *   PutChildrenElemNames( boost::property_tree::ptree* curNode, std::string path );
         *
         *   @param curNode (boost::property_tree::ptree) current node
         *   @param path    (std::string) path to elements and attribute you want to get under current node
         *   @return std::vector<std::string>  List of names
         */
    void SetDebugMode( bool isDebugMode=true );
        //!< Turn on or set debug mode to show behind messages about data treatments.
        /*!< Argument isDebugMode affects on QuietMode.
         *
         *   PutChildrenElemNames( std::string path );
         *
         *   @param isDebugMode (bool)
         *   @retval None
         */
};
#endif
