// ---------------------------------------------------------------------------
// 
//   Lily Engine alpha
// 
//   Copyright (c) 2010 Clifford Jolly
//     http://cliffjolly.com
//     cliff@cliffjolly.com
// 
// ---------------------------------------------------------------------------
// 
//   This program is free software; you can redistribute it and/or modify
//   it under the terms of the GNU General Public License as published by
//   the Free Software Foundation; either version 2 of the License, or
//   (at your option) any later version.
//  
//   This program is distributed in the hope that it will be useful, but
//   WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//   General Public License for more details.
// 
//   You should have received a copy of the GNU General Public License
//   along with this program; if not, write to the Free Software
//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
//   USA
// -------------------------- END HEADER -------------------------------------

#ifndef LILYPARSER_H
#define LILYPARSER_H

#include <map>
#include <vector>
#include <string>

namespace LilyParser {

    /// Parser node. Stores information in a hierarchy and can be saved to
    /// or read from text.
    class ParserNode {

        public:
 
            /// Get the name of this node. Top-level nodes will be
            /// named "root" by default.
            std::string getName(void);

            /// Get the value for this as a boolean. Returns true if
            /// the value is defined, otherwise returns false and does
            /// not set the value.
            bool getBooleanValue(const std::string &name, bool *value);

            /// Get the value for this as a string. Returns true if
            /// the value is defined, otherwise returns false and does
            /// not set the value.
            bool getStringValue(const std::string &name, std::string *value);

            /// Get the value for this as a float. Returns true if the
            /// value is defined, otherwise returns false and does not
            /// set the value.
            bool getFloatValue(const std::string &name, float *value);

            /// Get the value for this as an integer. Returns true if
            /// the value is defined, otherwise returns false and does
            /// not set the value.
            bool getIntValue(const std::string &name, int *value);
        
            /// Decode a binary buffer from the string, treating it as
            /// a string of hex values for bytes. Calling function
            /// owns the buffer and is responsible for cleaning it up.
            bool getBinaryValue(const std::string &name, char **buf, int *length);

            /// Encode a buffer as hex values and store it as a value
            /// on the node.
            void setBinaryValue(const std::string &name, char *buf, int length);

            /// Set the name of this node.
            void setName(const std::string &name);

            /// Set a value to "true" or "false".
            void setBooleanValue(const std::string &name, bool value);

            /// Set a value directly to a string.
            void setStringValue(const std::string &name, const std::string &value);

            /// Set a value to a string representation of a float.
            void setFloatValue(const std::string &name, float value);

            /// Set a value to a string representation of an integer.
            void setIntValue(const std::string &name, int value);

            /// Erase a value completely.
            void clearValue(const std::string &name);

            /// Get a child by its index.
            ParserNode *getChild(int index);

            /// Get the number of child nodes.
            unsigned int getNumChildren(void);

            /// Add a child to the end of the list of children.
            void addChildToEnd(ParserNode *node);

            /// Add a child to the start of the list of children
            /// (warning: slow).
            void addChildToStart(ParserNode *node);

            /// Output this ParserNode and all its children to an
            /// output stream in a format readable by parseBuffer()
            /// and parseString().
            void output(ostream &out, int indentLevel) const;

            /// Destructor.
            ~ParserNode(void);

            /// Default constructor.
            ParserNode(void);

            /// Constructor with a name.
            ParserNode(const std::string &name);

            /// Output this ParserNode as a string. Readable by
            /// parseString().
            std::string toString(void) const;

            /// Get the index of a child, optionally after some other index.
            int getChildIndexByName(const std::string &name, int after = -1);

            /// Just get the first child with this name.
            ParserNode *getChildByName(const std::string &name);

        private:

            std::map<std::string, std::string> values;
            std::vector<ParserNode*> children;
            std::string name;

    };

    /// Parse a buffer and get a ParserNode tree. Returns NULL on
    /// error and sets an error description in errorStr if errorStr is
    /// not NULL.
    ParserNode *parseBuffer(const char *buf, int length, std::string *errorStr = NULL);

    /// Parse a generic std::string and get a ParserNode tree. Returns
    /// NULL on error and sets an error description in errorStr if
    /// errorStr is not NULL.
    ParserNode *parseString(const std::string &str, std::string *errorStr = NULL);

    /// Output to an ostream.
    ostream &operator<<(ostream &out, const ParserNode &node);

    // TODO: istream input.

    /// Load and parse a file.
    ParserNode *loadAndParse(const std::string &fileName, std::string *errorStr = NULL);
}

#endif

