#ifndef  LIBE_PROPERTYLIST_H
#define  LIBE_PROPERTYLIST_H
/**
   author: stephan@wanderinghorse.net
   based on code by Rusty Ballinger (bozo@users.sourceforge.net)
   license: GPL

   EPropertyList is a class for holding arbitrary key/value pairs
   of numeric/string data. In includes save/load support.
*/

#include <iostream>
#include "EKeyValueParser.h"

/**
   License: Public Domain
   Author: stephan

   TODO: move many of the EKeyValueParser typedefs into this class and rename
   them to be consistent with the STL.
*/

class EPropertyList
{
public:

        typedef std::map<std::string,std::string> StringStringMap;
        typedef StringStringMap::iterator iterator;
        typedef StringStringMap::const_iterator const_iterator;
        typedef StringStringMap::value_type StringStringPair;
        

        
//         typedef std::map<std::string,bool> StringBoolMap;
//         typedef StringBoolMap::iterator StringBoolIterator;
//         typedef StringBoolMap::value_type StringBoolPair;

        typedef std::list<std::string> string_list;


        /**
           adds pl.toString() to os.
        */
        friend std::ostream & operator << (std::ostream &os, const EPropertyList &);

        /**
           adds pl.toString() to os.
        */
        friend std::string & operator << (std::string &os, const EPropertyList &pl );

        /**
           std::string propval = props["bar"]
           is functionally identical to getString("bar").
        */
        std::string operator[] ( const std::string & key ) const;


        /**
           Name may be a filename, though load() is not called automatically.
        */
        EPropertyList( const std::string &name = "" );
        virtual ~EPropertyList();

        /** 
            Name is currently used as a filename, though it may have other uses.
        */
        void setName( const std::string &name );
        const std::string & getName() const;

        /**
           Returns the number of items in our map.
        */
        int count() const;

        /**
         * Returns the value for key, or defaultVal if the key is not set.
         * Note to subclassers:
         * This is the "master" getter, so subclasses which want to generically 
         * alter getXXX() behaviour need only override this function.
         * If you override this, DO NOT use the like LIBE_{DEBUG,VERBOSE} macros
         * from within this function, or from any other getXXX() from this object;
         * doing so may cause an endless loop. Additionally, all other getXXX()
         * functions call this one, so do not call them from inside this function.
         */
        virtual std::string getString( const std::string &key, const std::string &defaultVal = std::string() ) const;

        /**
         * Sets key to val. Warning: when calling this, you should
         * pass a std::string(), and not rely on casting from a char *, for val.
         * Calling it like: set( "foo", "bar" ) is likely to call the boolean
         * version! To work around this call set( "foo", std::string("bar") )
         * or setString( "foo", "bar" ).
         */
        virtual void set( const std::string &key, std::string val );
        virtual void setString( const std::string &key, std::string val ); // use if you get type casting problems.
        /**
         * Sets key to val IF the key is not already set, else it does nothing.
         * Returns true if it does set the value, else false.
         * Use this to supply default values for not-already-set items, without having to
         * check if they're set.
         */
        virtual bool setIfNot( const std::string &key, std::string val );

        virtual void set( const std::string &key, bool val );
        virtual void setBool( const std::string &key, bool val ); // use if you get type casting problems.
        virtual bool getBool( const std::string &key, bool defaultVal ) const;
        virtual bool setIfNot( const std::string &key, bool val );


        virtual int getInt( const std::string &key, int defaultVal ) const;
        virtual void set( const std::string &key, int val );
        virtual void setInt( const std::string &key, int val ); // use if you get type casting problems.
        virtual bool setIfNot( const std::string &key, int val );

        virtual double getDouble( const std::string &key, double defaultVal ) const;
        virtual void set( const std::string &key, double val );
        virtual void setDouble( const std::string &key, double val ); // use if you get type casting problems.
        virtual bool setIfNot( const std::string &key, double val );

        virtual bool isSet( const std::string &key ) const;
        virtual bool unset( const std::string &key );
        virtual bool clear();

        /**
         * Returns the bool value of the passed string.
         * The following string values are considered equal to true:
         true, TRUE, True, t, T
         yes, YES, Yes, y, Y
         1
         * Anything else evaluates to false.
         * CASE IS IMPORTANT! (Sorry, when I learn how to easily lowercase a c++ string
         * I'll fix all that.)
         */
        static bool boolVal( const std::string &key );

        /**
         * Returns the first item in the data map.
         * You can use this to iterate:
         *   EPropertyList::iterator it = props.begin();
         *   while( it != props.end() ) { ... ++it; }
         */
        EPropertyList::iterator begin();
        EPropertyList::const_iterator begin() const;

        /**
         * The after-the-end iterator for the data map.
         */
        EPropertyList::iterator end();
        EPropertyList::const_iterator end() const;

        /**
         * Returns end() if the key is not in our map, otherise it returns
         * that iterator. Use the iterator's .first member to get the key,
         * and .second to get the value. However, you SHOULD call getString( (*iter) )
         * to get the value, so subclasses can do some funniness with the key,
         * like ESimpleCLParser does:
         *   std::string val;
         *   iter = foo.find( "key" );
         *   if( iter == foo.end() ) { return val; }
         *   return val = foo.getString( (*iter) );
         * This helps guaranty similar behaviour across subclasses.
         *
         * todo: make this the master getter, instead of getString(), for purposes
         * of overriding getXXX() behaviour?
         */
        virtual EPropertyList::iterator find( const std::string &key );

        /**
           merge() copies all properties from src to dest. It returns the
           number of properties copied, or -1 on a massive error (e.g.,
           if src/dest point to the same object).
        */
        static int merge( EPropertyList &src, EPropertyList &dest );

        /**
         * If filename is empty, the filename from the constructor or setName() is used.
         * If both are empty, false is returned.
         * Returns false on error, otherwise true.
         * Note that input lines like:
         *  key=
         * Are not considered valid, and will not be set!!!
         * if blanksToFalse == true, then these keys will be saved as boolean falses.
         * todo: make a form of load() which takes an istream.
         */
        virtual bool load( std::string filename = "", bool blanksToFalse=false );

        /**
           identical to load( string, bool ) except that reads from an input stream.
           Note that it does not open() nor close() the stream!
        */
        virtual bool load( std::istream &in, bool blanksToFalse=false );
        /**
         * If filename is empty, the filename from the constructor or setName() is used.
         * If both are empty, false is returned.
         * Returns false on error, otherwise true.
         * todo: make a version of save() which takes an ostream.
         */
        virtual bool save( std::string filename = "" );


        /**
         * Writes out a string containing the contents of this object and returns it.
         */
        virtual std::string toString() const;


        /**
           Returns the list of keys, ordered in their insertion order.
         */
        const EPropertyList::string_list & orderedKeys() const { return this->order; };


        /**
           If saveAtDestruction() returns true and this object's
           filename has been set then this object will try to save
           itself to that filename in it's destructor.
         */
        bool saveAtDestruction() const { return this->m_saveAtDtor; };
        void saveAtDestruction( bool b ) { this->m_saveAtDtor = b; };


protected:
        /**
         * Returns the internally-used StringStringMap (see the typedefs, above).
         */
        StringStringMap & getMap();


private:
        typedef std::map<char,bool> CharBoolMap;
        typedef CharBoolMap::value_type CharBoolPair;
        typedef std::map<std::string,bool> TrueMap;

        void init(std::string fn);
        std::string filename;
        StringStringMap map;
        CharBoolMap::iterator commentIt;
        mutable string_list order;
        std::string name;
        static TrueMap trues;
        static CharBoolMap commentChars;
        mutable char * number_buffer;
        bool m_saveAtDtor;
};
#endif //  LIBE_PROPERTYLIST_H
