    //------------------------------------------------------------------------------
    // emRec.h - Recordable data structures
    //
    // Copyright (C) 2005-2010 Oliver Hamann.
    //
    // Homepage: http://eaglemode.sourceforge.net/
    //
    // This program is free software: you can redistribute it and/or modify it under
    // the terms of the GNU General Public License version 3 as published by the
    // Free Software Foundation.
    //
    // 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 version 3 for
    // more details.
    //
    // You should have received a copy of the GNU General Public License version 3
    // along with this program. If not, see <http://www.gnu.org/licenses/>.
    //------------------------------------------------------------------------------

    #ifndef emRec_h
    #define emRec_h

    #ifndef emColor_h
    #include <emCore/emColor.h>
    #endif

    class emRecReader;
    class emRecWriter;
    class emStructRec;

    class emRecNode : public emUncopyable {
    public:
            virtual ~emRecNode();
    private:
            friend class emRec;
            friend class emRecListener;
            virtual bool IsListener() const = 0;
            virtual void ChildChanged() = 0;
            emRecNode * UpperNode;
    };

    //==============================================================================
    //=================================== emRec ====================================
    //==============================================================================

    class emRec : public emRecNode {

    public:

            // This is the abstract base class for all record classes. The record
            // classes can be used to design data structures whose contents can be
            // converted to and from ASCII text. A typical example is the definition
            // of a configuration file format. It takes just a few lines of
            // programming to define a new file format and a structured C++
            // interface with fastest get-methods and operators on the data fields.
            // A disadvantage is that the records may take round about ten times
            // more memory than a raw C data structure would take. Here comes a
            // tiny example:
            //
            // Assumed our data structure would look like this in simple C:
            //
            //   struct Person {
            //     char Name[64];
            //     int Age;
            //     unsigned Male : 1;
            //   };
            //
            //   struct Person Persons[2];
            //
            // With the record classes, it looks like this:
            //
            //   class Person : public emStructRec {
            //   public:
            //     Person();
            //     emStringRec Name;
            //     emIntRec Age;
            //     emBoolRec Male;
            //   };
            //
            //   Person::Person() :
            //     emStructRec(),
            //     Name(this,"name"),
            //     Age(this,"age"),
            //     Male(this,"male")
            //   {}
            //
            //   emTArrayRec<Person> Persons;
            //
            // This fills the data structure with some information and writes it to
            // a file:
            //
            //   int main(int argc, char * argv[])
            //   {
            //     Persons.SetCount(2);
            //     Persons[0].Name="Fred";
            //     Persons[0].Age=12;
            //     Persons[0].Male=true;
            //     Persons[1].Name="Clara";
            //     Persons[1].Age=11;
            //     Persons[1].Male=false;
            //     Persons.TrySave("test.rec");
            //   }
            //
            // Here is the resulting contents of the file test.rec:
            //
            //   {
            //     name = "Fred"
            //     age = 12
            //     male = yes
            //   }
            //   {
            //     name = "Clara"
            //     age = 11
            //     male = no
            //   }

            emRec();
                    // Construct this record without being a member of an
                    // emStructRec.

            emRec(emStructRec * parent, const char * varIdentifier);
                    // Construct this record as a member of an emStructRec.
                    // Arguments:
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.

            virtual ~emRec();
                    // Destructor.

            emRec * GetParent();
            const emRec * GetParent() const;
                    // Get the parent record. Returns NULL if this is a root record.
                    // (This is not super-fast, because the chain of listeners is
                    // walked to find the parent).

            emRec * GetRoot();
            const emRec * GetRoot() const;
                    // Get the root record (this is not super-fast).

            virtual const char * GetFormatName() const;
                    // If this record is the root of records defining a file format,
                    // this method should be overloaded and it should return a handy
                    // name for the file format. Thereby, emRecWriter and
                    // emRecReader are writing and checking a file format magic at
                    // the beginning of the file. The default implementation returns
                    // NULL which means to have no file format magic.

            void TryLoad(const emString & filePath) throw(emString);
            void TrySave(const emString & filePath) throw(emString);
                    // Load or save this tree of records from or to a file.
                    // Arguments:
                    //   filePath - Path/name of the file.

            void TryLoadFromMem(const char * buf, int len) throw(emString);
            void TryLoadFromMem(const emArray<char> & buf) throw(emString);
            void SaveToMem(emArray<char> & buf);
                    // Load or save this tree of records from or to memory.
                    // SaveToMem adds the data to the array without emptying it
                    // first.

            void TryCopy(emRec & source) throw(emString);
            void Copy(emRec & source);
                    // Copy the given tree of records to this tree of records via
                    // the SaveToMem and TryLoadFromMem methods. This is slow and
                    // works only if the records are compatible. The second version
                    // calls emFatalError on error.

            virtual void SetToDefault() = 0;
                    // Set this record to default state. When reading an
                    // emStructRec, omitted members are set to their defaults.

            virtual bool IsSetToDefault() const = 0;
                    // Ask whether this record is set to its default state. When
                    // writing an emStructRec, members with default state may be
                    // omitted.

            virtual void TryStartReading(emRecReader & reader) throw(emString) = 0;
            virtual bool TryContinueReading(emRecReader & reader) throw(emString) = 0;
            virtual void QuitReading() = 0;
            virtual void TryStartWriting(emRecWriter & writer) throw(emString) = 0;
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString) = 0;
            virtual void QuitWriting() = 0;
                    // This is only to be called by emRecReader/Writer and through
                    // recursion in the tree. Try to read or write this tree of
                    // records via the given reader or writer. First, the start
                    // method is called, and then the continue method is called
                    // again and again until it returns true. The quit method is
                    // called at the end, even on error or when aborting. The quit
                    // mechanism should be quite stable, because with
                    // emRecFileModel, it could happen that quit is called in
                    // response to OnChanged through a user modification.

            virtual emUInt64 CalcRecMemNeed() const = 0;
                    // Calculate best known number of bytes, which are allocated for
                    // this record, or which will be allocated after reading has
                    // completed.

            static void CheckIdentifier(const char * identifier);
                    // "identifiers" are names of variables, enumeration variants
                    // and so on. The syntactical rules are the same as with
                    // identifiers in the C programming language: begin with a
                    // letter or underscore and continue with letter, underscore or
                    // digit. But they are not case sensitive. This functions checks
                    // whether the given string is a valid identifier. If not,
                    // emFatalError is called.

    protected:

            void Changed();
                    // This must be called by derived classes after each change of
                    // the record, even through TryStartReading and
                    // TryContinueReading, but never through constructors or
                    // destructors. It informs the listeners of all the records on
                    // the path from this record up to the root record.

            void BeTheParentOf(emRec * child);
                    // This makes this record the parent of the given child. It is
                    // called by dynamic containers like emUnionRec and emArrayRec
                    // on creation of children.

    private:
            virtual bool IsListener() const;
            virtual void ChildChanged();
    };

    inline emRec::emRec()
    {
            UpperNode=NULL;
    }

    inline void emRec::Changed()
    {
            if (UpperNode) UpperNode->ChildChanged();
    }

    //==============================================================================
    //=============================== emRecListener ================================
    //==============================================================================

    class emRecListener : public emRecNode {

    public:

            // Abstract base class for a listener on a record and it descendants.

            emRecListener(emRec * rec=NULL);
            virtual ~emRecListener();

            const emRec * GetListenedRec() const;
            emRec * GetListenedRec();
            void SetListenedRec(emRec * rec);
                    // Get/set the record to be listened. NULL means not to listen
                    // any record. On deletion of the listened record, this is
                    // automatically set to NULL.

    protected:

            virtual void OnRecChanged() = 0;
                    // Called on each change of the record and its descendants. This
                    // is a synchronous call - the implementation must not modify
                    // the records or the listeners.

    private:
            virtual bool IsListener() const;
            virtual void ChildChanged();
            emRec * Rec;
    };

    inline const emRec * emRecListener::GetListenedRec() const
    {
            return Rec;
    }

    inline emRec * emRecListener::GetListenedRec()
    {
            return Rec;
    }

    //==============================================================================
    //=============================== emRecAllocator ===============================
    //==============================================================================

    typedef emRec * (* emRecAllocator)();
            // Data type for a pointer to function which can allocate a new record.
            // This is used for dynamic containers like emUnionRec and emArrayRec.

    #define EM_DEFAULT_REC_ALLOCATOR(REC) (&emDfltRecAllocImp<REC >::Allocate)
            // This macro expands to an emRecAllocator which allocates a record of
            // type REC with its default constructor.

    // private stuff for the macro above.
    template <class REC> class emDfltRecAllocImp : public emUnconstructable {
    public:
            static emRec * Allocate() { return new REC(); }
    };

    //==============================================================================
    //================================= emBoolRec ==================================
    //==============================================================================

    class emBoolRec : public emRec {

    public:

            // Record class for a boolean value.

            emBoolRec(bool defaultValue=false);
            emBoolRec(emStructRec * parent, const char * varIdentifier,
                      bool defaultValue=false);
                    // Construct this record.
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.
                    //   defaultValue  - The default value for this boolean record.

            bool Get() const;
            operator bool () const;
                    // Get the boolean value.

            void Set(bool value);
            emBoolRec & operator = (bool value);
                    // Set the boolean value.

            void Invert();
                    // Invert the boolean value.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private:
            bool DefaultValue, Value;
    };

    inline bool emBoolRec::Get() const
    {
            return Value;
    }

    inline emBoolRec::operator bool () const
    {
            return Value;
    }

    inline emBoolRec & emBoolRec::operator = (bool value)
    {
            Set(value);
            return *this;
    }

    //==============================================================================
    //================================== emIntRec ==================================
    //==============================================================================

    class emIntRec : public emRec {

    public:

            // Record class for an integer value.

            emIntRec(int defaultValue=0, int minValue=INT_MIN,
                     int maxValue=INT_MAX);
            emIntRec(emStructRec * parent, const char * varIdentifier,
                     int defaultValue=0, int minValue=INT_MIN,
                     int maxValue=INT_MAX);
                    // Construct this record.
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.
                    //   defaultValue  - The default value for this integer record.
                    //   minValue      - The value will never be less than this.
                    //   maxValue      - The value will never be greater than this.

            int Get() const;
            operator int () const;
                    // Get the integer value.

            void Set(int value);
            emIntRec & operator = (int value);
                    // Set the integer value. It is clipped if it would be less than
                    // the minimum value or greater than the maximum value.

            int GetMinValue() const;
            int GetMaxValue() const;
                    // Get minimum and maximum values.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private:
            int DefaultValue, MinValue, MaxValue, Value;
    };

    inline int emIntRec::Get() const
    {
            return Value;
    }

    inline emIntRec::operator int () const
    {
            return Value;
    }

    inline emIntRec & emIntRec::operator = (int value)
    {
            Set(value);
            return *this;
    }

    inline int emIntRec::GetMinValue() const
    {
            return MinValue;
    }

    inline int emIntRec::GetMaxValue() const
    {
            return MaxValue;
    }

    //==============================================================================
    //================================ emDoubleRec =================================
    //==============================================================================

    class emDoubleRec : public emRec {

    public:

            // Record class for a double value.

            emDoubleRec(double defaultValue=0.0, double minValue=-3.4E+38,
                        double maxValue=3.4E+38);
            emDoubleRec(emStructRec * parent, const char * varIdentifier,
                        double defaultValue=0.0, double minValue=-3.4E+38,
                        double maxValue=3.4E+38);
                    // Construct this record.
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.
                    //   defaultValue  - The default value for this double record.
                    //   minValue      - The value will never be less than this.
                    //   maxValue      - The value will never be greater than this.

            double Get() const;
            operator double () const;
                    // Get the value.

            void Set(double value);
            emDoubleRec & operator = (double value);
                    // Set the double value. It is clipped if it would be less than
                    // the minimum or greater than the maximum.

            double GetMinValue() const;
            double GetMaxValue() const;
                    // Get minimum and maximum values.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private:
            double DefaultValue, MinValue, MaxValue, Value;
    };

    inline double emDoubleRec::Get() const
    {
            return Value;
    }

    inline emDoubleRec::operator double () const
    {
            return Value;
    }

    inline emDoubleRec & emDoubleRec::operator = (double value)
    {
            Set(value);
            return *this;
    }

    inline double emDoubleRec::GetMinValue() const
    {
            return MinValue;
    }

    inline double emDoubleRec::GetMaxValue() const
    {
            return MaxValue;
    }

    //==============================================================================
    //================================= emEnumRec ==================================
    //==============================================================================

    class emEnumRec : public emRec {

    public:

            // Record class for an enumeration value. It is like emIntRec, but each
            // possible value is given an identifier.

            emEnumRec(int defaultValue, const char * identifier0, ...);
            emEnumRec(emStructRec * parent, const char * varIdentifier,
                      int defaultValue, const char * identifier0, ...);
                    // Construct this record.
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.
                    //   defaultValue  - The default value for this enumeration
                    //                   record.
                    //   identifier0   - The identifier for value=0. The identifier
                    //                   is not copied - the pointer must be valid
                    //                   for the life time of this record.
                    //   ...           - Any number of further identifiers for
                    //                   values 1, 2, 3 and so on, terminated by a
                    //                   NULL.

            virtual ~emEnumRec();
                    // Destructor.

            int Get() const;
            operator int () const;
                    // Get the value.

            void Set(int value);
            emEnumRec & operator = (int value);
                    // Set the value. It is clipped if out of range.

            const char * GetIdentifier() const;
                    // Get the identifier for the current value.

            int GetIdentifierCount();
                    // Get number of possible values.

            const char * GetIdentifierOf(int value);
                    // Get the identifier for the given value. Returns NULL if the
                    // value is out of range.

            int GetValueOf(const char * identifier);
                    // Get the value for the given identifier. Returns -1 if there
                    // is no such identifier.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private:

            void Init(int defaultValue, const char * identifier0, va_list args);

            const char * * Identifiers;
            int IdentifierCount, DefaultValue, Value;
    };

    inline int emEnumRec::Get() const
    {
            return Value;
    }

    inline emEnumRec::operator int () const
    {
            return Value;
    }

    inline emEnumRec & emEnumRec::operator = (int value)
    {
            Set(value);
            return *this;
    }

    inline const char * emEnumRec::GetIdentifier() const
    {
            return Identifiers[Value];
    }

    inline int emEnumRec::GetIdentifierCount()
    {
            return IdentifierCount;
    }

    //==============================================================================
    //================================= emFlagsRec =================================
    //==============================================================================

    class emFlagsRec : public emRec {

    public:

            // Record class for a set of flags. It is a bit mask where each possible
            // bit is given an identifier.

            emFlagsRec(int defaultValue, const char * identifier0, ...);
            emFlagsRec(emStructRec * parent, const char * varIdentifier,
                      int defaultValue, const char * identifier0, ...);
                    // Construct this record.
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.
                    //   defaultValue  - The default value for this enumeration
                    //                   record.
                    //   identifier0   - The identifier for bit 0. The identifier
                    //                   is not copied - the pointer must be valid
                    //                   for the life time of this record.
                    //   ...           - Any number of further identifiers for
                    //                   bits 1, 2, 3, ... 31, terminated by a
                    //                   NULL.

            virtual ~emFlagsRec();
                    // Destructor.

            int Get() const;
            operator int () const;
                    // Get the value. It's the bit mask.

            void Set(int value);
            emFlagsRec & operator = (int value);
                    // Set the value. Undefined flag bits are set to zero.

            int GetIdentifierCount();
                    // Get number of possible flag bits.

            const char * GetIdentifierOf(int bit);
                    // Get the identifier for the given flag bit (0...31). Returns
                    // NULL when no identifier has been defined for the bit.

            int GetBitOf(const char * identifier);
                    // Get the flag bit for the given identifier. Returns -1 if
                    // there is no such identifier.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private:

            void Init(int defaultValue, const char * identifier0, va_list args);

            const char * * Identifiers;
            int IdentifierCount, DefaultValue, Value;
    };

    inline int emFlagsRec::Get() const
    {
            return Value;
    }

    inline emFlagsRec::operator int () const
    {
            return Value;
    }

    inline emFlagsRec & emFlagsRec::operator = (int value)
    {
            Set(value);
            return *this;
    }

    inline int emFlagsRec::GetIdentifierCount()
    {
            return IdentifierCount;
    }

    //==============================================================================
    //================================ emStringRec =================================
    //==============================================================================

    class emStringRec : public emRec {

    public:

            // Record class for an emString value.

            emStringRec(const emString & defaultValue=emString());
            emStringRec(emStructRec * parent, const char * varIdentifier,
                        const emString & defaultValue=emString());
                    // Construct this record.
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.
                    //   defaultValue  - The default value for this string record.

            virtual ~emStringRec();
                    // Destructor.

            const emString & Get() const;
            operator const emString & () const;
                    // Get the string value.

            void Set(const emString & value);
            emStringRec & operator = (const emString & value);
                    // Set the string value.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private:
            emString DefaultValue, Value;
    };

    inline const emString & emStringRec::Get() const
    {
            return Value;
    }

    inline emStringRec::operator const emString & () const
    {
            return Value;
    }

    inline emStringRec & emStringRec::operator = (const emString & value)
    {
            Set(value);
            return *this;
    }

    //==============================================================================
    //================================= emColorRec =================================
    //==============================================================================

    class emColorRec : public emRec {

    public:

            // Record class for an emColor value.

            emColorRec(emColor defaultValue=emColor(0,0,0,255),
                       bool haveAlpha=false);
            emColorRec(emStructRec * parent, const char * varIdentifier,
                       emColor defaultValue=emColor(0,0,0,255),
                       bool haveAlpha=false);
                    // Construct this record.
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.
                    //   defaultValue  - The default value for this color record.
                    //   haveAlpha     - false if the color has to be opaque.

            emColor Get() const;
            operator emColor () const;
                    // Get the color value.

            void Set(emColor value);
            emColorRec & operator = (emColor value);
                    // Set the color value. The alpha channel is set to 255 if this
                    // color record has to be opaque.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private:
            emColor DefaultValue, Value;
            bool HaveAlpha;
    };

    inline emColor emColorRec::Get() const
    {
            return Value;
    }

    inline emColorRec::operator emColor () const
    {
            return Value;
    }

    inline emColorRec & emColorRec::operator = (emColor value)
    {
            Set(value);
            return *this;
    }

    //==============================================================================
    //================================ emStructRec =================================
    //==============================================================================

    class emStructRec : public emRec {

    public:

            // Base class for a structured record class. The idea is to give derived
            // classes some records as member variables.

            emStructRec();
            emStructRec(emStructRec * parent, const char * varIdentifier);
                    // Construct this record.
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.

            virtual ~emStructRec();
                    // Destructor.

            int GetCount() const;
                    // Get number of members.

            const emRec & Get(int index) const;
            emRec & Get(int index);
            const emRec & operator [] (int index) const;
            emRec & operator [] (int index);
                    // Get a reference to a member. The index must be within the
                    // range of 0 to GetCount()-1.

            const char * GetIdentifierOf(int index);
                    // Get the identifier for the given member index. Returns NULL
                    // if the index is out of range.

            int GetIndexOf(emRec * member);
                    // Get the member index for the given member pointer. Returns -1
                    // if there is no such member.

            int GetIndexOf(const char * identifier);
                    // Get the member index for the given identifier. Returns -1 if
                    // there is no such identifier.

            virtual bool ShallWriteOptionalOnly(const emRec * child) const;
                    // Whether the given member should not be written when it has
                    // default state. The default implementation always returns
                    // false.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private: friend class emRec;

            void AddMember(emRec * member, const char * identifier);

            struct MemberType {
                    const char * Identifier;
                    emRec * Record;
            };

            struct RWStateType {
                    int Pos;
                    bool ChildReady;
                    bool Empty;
                    emByte Map[1];
            };

            int Count, Capacity;
            MemberType * Members;
            RWStateType * RWState;
    };

    inline int emStructRec::GetCount() const
    {
            return Count;
    }

    inline const emRec & emStructRec::Get(int index) const
    {
            return *Members[index].Record;
    }

    inline emRec & emStructRec::Get(int index)
    {
            return *Members[index].Record;
    }

    inline const emRec & emStructRec::operator [] (int index) const
    {
            return *Members[index].Record;
    }

    inline emRec & emStructRec::operator [] (int index)
    {
            return *Members[index].Record;
    }

    //==============================================================================
    //================================= emUnionRec =================================
    //==============================================================================

    class emUnionRec : public emRec {

    public:

            // Record class for a union. An instance of this class manages one child
            // record with variable type. The possible types are called the
            // "variants".

            emUnionRec(int defaultVariant,
                       const char * identifier0, emRecAllocator allocator0, ...);
            emUnionRec(emStructRec * parent, const char * varIdentifier,
                       int defaultVariant,
                       const char * identifier0, emRecAllocator allocator0, ...);
                    // Construct this record.
                    //   parent         - The emStructRec this record is a member
                    //                    of.
                    //   varIdentifier  - Identifier for this record within the
                    //                    emStructRec. The string is not copied -
                    //                    the pointer must be valid for the life
                    //                    time of this record.
                    //   defaultVariant - Index of the default variant.
                    //   identifier0    - Identifier for the first variant.
                    //                    The string is not copied - the pointer
                    //                    must be valid for the life time of the
                    //                    record.
                    //   allocator0     - Allocator function for the first variant.
                    //   ...            - Any number of further pairs of identifier
                    //                    and allocator, terminated by a NULL.

            virtual ~emUnionRec();
                    // Destructor.

            int GetVariant() const;
                    // Get the current variant index.

            void SetVariant(int variant);
                    // Set the current variant index. If it is a change, the old
                    // child record is deleted and a new one is created by calling
                    // the corresponding allocator function.

            emRec & Get();
            const emRec & Get() const;
                    // Get a reference to the child record.

            int GetVariantCount() const;
                    // Get number of variants.

            const char * GetIdentifierOf(int variant);
                    // Get the identifier for the given variant index. Returns NULL
                    // if there is no such variant.

            int GetVariantOf(const char * identifier);
                    // Get the variant index for the given identifier. Returns -1 if
                    // there is no such identifier.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private:

            void Init(int defaultVariant, const char * identifier0,
                      emRecAllocator allocator0, va_list args);

            struct VariantType {
                    const char * Identifier;
                    emRecAllocator Allocator;
            };

            VariantType * TypeArray;
            int VariantCount, DefaultVariant, Variant;
            emRec * Record;
    };

    inline int emUnionRec::GetVariant() const
    {
            return Variant;
    }

    inline emRec & emUnionRec::Get()
    {
            return *Record;
    }

    inline const emRec & emUnionRec::Get() const
    {
            return *Record;
    }

    inline int emUnionRec::GetVariantCount() const
    {
            return VariantCount;
    }

    //==============================================================================
    //================================= emArrayRec =================================
    //==============================================================================

    class emArrayRec : public emRec {

    public:

            // Record class for an array of records. Please even see the template
            // version emTArrayRec more below.

            emArrayRec(emRecAllocator allocator, int minCount=0,
                       int maxCount=INT_MAX);
            emArrayRec(emStructRec * parent, const char * varIdentifier,
                       emRecAllocator allocator, int minCount=0,
                       int maxCount=INT_MAX);
                    // Construct this record.
                    //   parent        - The emStructRec this record is a member of.
                    //   varIdentifier - Identifier for this record within the
                    //                   emStructRec. The string is not copied - the
                    //                   pointer must be valid for the life time of
                    //                   this record.
                    //   allocator     - Allocator function for elements of the
                    //                   array.
                    //   minCount      - Minimum number of elements. This is even
                    //                   the default number of elements.
                    //   maxCount      - Maximum number of elements.

            virtual ~emArrayRec();
                    // Destructor.

            int GetCount() const;
                    // Get number of elements.

            void SetCount(int count);
                    // Set number of elements. It is clipped if out of range. New
                    // elements are set to their defaults.

            void Insert(int index, int insCount=1);
            void Remove(int index, int remCount=1);
                    // Insert or remove elements at a particular position. The
                    // number of elements is clipped if the resulting total number
                    // would be out of range. New elements are set to their
                    // defaults.

            int GetMinCount() const;
            int GetMaxCount() const;
                    // Get minimum and maximum number of elements.

            const emRec & Get(int index) const;
            emRec & Get(int index);
            const emRec & operator [] (int index) const;
            emRec & operator [] (int index);
                    // Get a reference to an element. The index must be within the
                    // range of 0 to GetCount()-1.

            virtual void SetToDefault();
            virtual bool IsSetToDefault() const;
            virtual void TryStartReading(emRecReader & reader) throw(emString);
            virtual bool TryContinueReading(emRecReader & reader) throw(emString);
            virtual void QuitReading();
            virtual void TryStartWriting(emRecWriter & writer) throw(emString);
            virtual bool TryContinueWriting(emRecWriter & writer) throw(emString);
            virtual void QuitWriting();
            virtual emUInt64 CalcRecMemNeed() const;
                    // See emRec.

    private:

            void Init(emRecAllocator allocator, int minCount, int maxCount);

            emRecAllocator Allocator;
            int MinCount, MaxCount, Count, Capacity, RWPos;
            emRec * * Array;
            bool RWChildReady;
    };

    inline int emArrayRec::GetCount() const
    {
            return Count;
    }

    inline int emArrayRec::GetMinCount() const
    {
            return MinCount;
    }

    inline int emArrayRec::GetMaxCount() const
    {
            return MaxCount;
    }

    inline const emRec & emArrayRec::Get(int index) const
    {
            return *Array[index];
    }

    inline emRec & emArrayRec::Get(int index)
    {
            return *Array[index];
    }

    inline const emRec & emArrayRec::operator [] (int index) const
    {
            return *Array[index];
    }

    inline emRec & emArrayRec::operator [] (int index)
    {
            return *Array[index];
    }

    //==============================================================================
    //================================ emTArrayRec =================================
    //==============================================================================

    template <class REC> class emTArrayRec : public emArrayRec {

    public:

            // Template version of emArrayRec.

            emTArrayRec(int minCount=0, int maxCount=INT_MAX);
            emTArrayRec(emStructRec * parent, const char * varIdentifier,
                        int minCount=0, int maxCount=INT_MAX);
                    // Like with emArrayRec, but the allocator is
                    // EM_DEFAULT_REC_ALLOCATOR(REC).

            const REC & Get(int index) const;
            REC & Get(int index);
            const REC & operator [] (int index) const;
            REC & operator [] (int index);
                    // Like with emArrayRec, but the results are casted...
    };

    template <class REC> inline emTArrayRec<REC>::emTArrayRec(
            int minCount, int maxCount
    )
            : emArrayRec(EM_DEFAULT_REC_ALLOCATOR(REC),minCount,maxCount)
    {
    }

    template <class REC> inline emTArrayRec<REC>::emTArrayRec(
            emStructRec * parent, const char * varIdentifier, int minCount,
            int maxCount
    )
            : emArrayRec(parent,varIdentifier,EM_DEFAULT_REC_ALLOCATOR(REC),
                          minCount,maxCount)
    {
    }

    template <class REC> inline const REC & emTArrayRec<REC>::Get(int index) const
    {
            return (const REC &)emArrayRec::Get(index);
    }

    template <class REC> inline REC & emTArrayRec<REC>::Get(int index)
    {
            return (REC &)emArrayRec::Get(index);
    }

    template <class REC> inline const REC & emTArrayRec<REC>::operator [] (
            int index
    ) const
    {
            return (const REC &)emArrayRec::Get(index);
    }

    template <class REC> inline REC & emTArrayRec<REC>::operator [] (int index)
    {
            return (REC &)emArrayRec::Get(index);
    }

    //==============================================================================
    //================================ emRecReader =================================
    //==============================================================================

    class emRecReader : public emUncopyable {

    public:

            // Abstract base class for reading a tree of records from a source.

            emRecReader();
            virtual ~emRecReader();

            void TryStartReading(emRec & root) throw(emString);
                    // Start reading.
                    // Arguments:
                    //   root - The root of the records to filled.

            bool TryContinueReading() throw(emString);
                    // Continue reading. Returns true when ready, otherwise
                    // TryContinueReading has to be called again.

            void TryFinishReading() throw(emString);
                    // Continue reading until ready.

            void QuitReading();
                    // Abort any reading.

            // - - The following things are for implementing emRec derivatives - -

            enum ElementType {
                    ET_DELIMITER,
                    ET_IDENTIFIER,
                    ET_INT,
                    ET_DOUBLE,
                    ET_QUOTED,
                    ET_END
            };

            ElementType TryPeekNext(char * pDelimiter=NULL) throw(emString);
                    // Peek for the type of the next syntactical element to be read.
                    // If it is ET_DELIMITER and if pDelimiter is not NULL,
                    // *pDelimiter is set to the delimiter character,

            char TryReadDelimiter() throw(emString);
                    // Read the next syntactical element as a delimiter or throw an
                    // error. Currently, a delimiter can be any character except for
                    // white space, letters, digits, '#', '_' and '"'. The
                    // characters '.', '-' and '+' can be delimiters only if not
                    // confusable with numbers.

            void TryReadCertainDelimiter(char delimiter) throw(emString);
                    // Read the next syntactical element as the given delimiter or
                    // throw an error.

            const char * TryReadIdentifier() throw(emString);
                    // Read the next syntactical element as an identifier or throw
                    // an error.

            int TryReadInt() throw(emString);
                    // Read the next syntactical element as an integer value or
                    // throw an error.

            double TryReadDouble() throw(emString);
                    // Read the next syntactical element as a double value or throw
                    // an error.

            const char * TryReadQuoted() throw(emString);
                    // Read and unquote the next syntactical element as a quoted
                    // string or throw an error.

            void ThrowElemError(const char * text) const throw(emString);
                    // Throw an error containing the file name, the current line
                    // number and the given text.

            void ThrowSyntaxError() const throw(emString);
                    // Like ThrowElemError("syntax error")

            const emRec * GetRootRec() const;
                    // Get the root record of the tree currently read or NULL.

    protected:

            virtual int TryRead(char * buf, int maxLen) throw(emString) = 0;
                    // Read up to maxLen bytes from the source into the given
                    // buffer, or throw an error. Return the number of bytes read,
                    // or 0 if the end of source has been reached.

            virtual void TryClose() throw(emString) = 0;
                    // Close the source, or throw an error.

            virtual const char * GetSourceName() const = 0;
                    // Get the file name or another identification. This is required
                    // for making error messages.

    private:

            void SetMinNextBufSize(int minSize);
            void TryNextChar() throw(emString);
            void TryParseNext() throw(emString);

            emRec * Root;
            bool RootQuitPending;
            bool ClosePending;
            int Line;
            bool NextEaten;
            int NextLine;
            ElementType NextType;
            char NextDelimiter;
            char * NextBuf;
            int NextBufSize;
            int NextInt;
            double NextDouble;
            int NextChar;
    };

    inline const emRec * emRecReader::GetRootRec() const
    {
            return Root;
    }

    //==============================================================================
    //================================ emRecWriter =================================
    //==============================================================================

    class emRecWriter : public emUncopyable {

    public:

            // Abstract base class for writing a tree of records to a target.

            emRecWriter();
            virtual ~emRecWriter();

            void TryStartWriting(emRec & root) throw(emString);
                    // Start writing.
                    // Arguments:
                    //   root - The root of the records to be written.

            bool TryContinueWriting() throw(emString);
                    // Continue writing. Returns true when ready, otherwise
                    // TryContinueWriting has to be called again.

            void TryFinishWriting() throw(emString);
                    // Continue writing until ready.

            void QuitWriting();
                    // Abort any writing.

            // - - The following things are for implementing emRec derivatives - -

            void TryWriteDelimiter(char c) throw(emString);
                    // Write the given delimiter character.

            void TryWriteIdentifier(const char * idf) throw(emString);
                    // Write the given identifier.

            void TryWriteInt(int i) throw(emString);
                    // Write the given integer value.

            void TryWriteDouble(double d) throw(emString);
                    // Write the given double value.

            void TryWriteQuoted(const char * q) throw(emString);
                    // Quote and write the given string.

            void TryWriteSpace() throw(emString);
                    // Write a space character.

            void TryWriteNewLine() throw(emString);
                    // Write a new-line character.

            void TryWriteIndent() throw(emString);
                    // Write an indent (to be called only at beginning of a new
                    // line). It is a number of tabulator characters.

            void IncIndent();
            void DecIndent();
                    // Increase or decrease the number of tabulator characters to be
                    // written by TryWriteIndent.

            const emRec * GetRootRec() const;
                    // Get the root record of the tree currently written or NULL.

    protected:

            virtual void TryWrite(const char * buf, int len) throw(emString) = 0;
                    // Write len bytes from the given buffer to the target, or throw
                    // an error.

            virtual void TryClose() throw(emString) = 0;
                    // Flush and close the target, or throw an error.

    private:

            void TryWriteChar(char c);
            void TryWriteString(const char * s);

            emRec * Root;
            bool RootQuitPending;
            bool ClosePending;
            int Indent;
    };

    inline void emRecWriter::IncIndent()
    {
            Indent++;
    }

    inline void emRecWriter::DecIndent()
    {
            Indent--;
    }

    inline const emRec * emRecWriter::GetRootRec() const
    {
            return Root;
    }

    //==============================================================================
    //============================== emRecFileReader ===============================
    //==============================================================================

    class emRecFileReader : public emRecReader {

    public:

            // Class for reading a tree of records from a regular file.

            emRecFileReader();
            virtual ~emRecFileReader();

            void TryStartReading(emRec & root,
                                 const emString & filePath) throw(emString);
                    // Start reading.
                    // Arguments:
                    //   root     - The root of the tree of records to be read from
                    //              the file.
                    //   filePath - Path/name of the file.

            emUInt64 GetFileSize() const;
                    // Size of the file.

            emUInt64 GetFilePos() const;
                    // Read position in the file.

            double GetProgress() const;
                    // Progress in percent.

    protected:

            virtual int TryRead(char * buf, int maxLen) throw(emString);
            virtual void TryClose() throw(emString);
            virtual const char * GetSourceName() const;

    private:

            emString FilePath;
            FILE * File;
            emUInt64 FileSize, FilePos;
    };

    inline emUInt64 emRecFileReader::GetFileSize() const
    {
            return FileSize;
    }

    inline emUInt64 emRecFileReader::GetFilePos() const
    {
            return FilePos;
    }

    //==============================================================================
    //============================== emRecFileWriter ===============================
    //==============================================================================

    class emRecFileWriter : public emRecWriter {

    public:

            // Class for writing a tree of records to a regular file.

            emRecFileWriter();
            virtual ~emRecFileWriter();

            void TryStartWriting(emRec & root,
                                 const emString & filePath) throw(emString);
                    // Start writing.
                    // Arguments:
                    //   root     - The root of the tree of records to be written to
                    //              the file.
                    //   filePath - Path/name of the file.

    protected:

            virtual void TryWrite(const char * buf, int len) throw(emString);
            virtual void TryClose() throw(emString);

    private:

            emString FilePath;
            FILE * File;
    };

    //==============================================================================
    //=============================== emRecMemReader ===============================
    //==============================================================================

    class emRecMemReader : public emRecReader {

    public:

            // Class for reading a tree of records from memory.

            emRecMemReader();

            void TryStartReading(emRec & root, const char * buf,
                                 int len) throw(emString);
                    // Start reading.
                    // Arguments:
                    //   root  - The root of the tree of records to be read from
                    //           memory.
                    //   buf   - Memory buffer to be read, must be valid until
                    //           reading has finished.
                    //   len   - Number of bytes in the buffer.

    protected:

            virtual int TryRead(char * buf, int maxLen) throw(emString);
            virtual void TryClose() throw(emString);
            virtual const char * GetSourceName() const;

    private:

            const char * MemPos, * MemEnd;
    };

    //==============================================================================
    //=============================== emRecMemWriter ===============================
    //==============================================================================

    class emRecMemWriter : public emRecWriter {

    public:

            // Class for writing a tree of records to memory.

            emRecMemWriter();
            virtual ~emRecMemWriter();

            void TryStartWriting(emRec & root,
                                 emArray<char> & buf) throw(emString);
                    // Start writing. This and the other Try methods should never
                    // fail.
                    // Arguments:
                    //   root - The root of the tree of records to be written to
                    //          memory.
                    //   buf  - Memory buffer where the output is to be added. The
                    //          reference must be valid until the writing has
                    //          finished.

    protected:

            virtual void TryWrite(const char * buf, int len) throw(emString);
            virtual void TryClose() throw(emString);

    private:

            emArray<char> * Buf;
    };

    #endif