#ifndef __ZString_h__
# define __ZString_h__

# include <ostream>
# include <stack>
# include <string.h>
# include <string>
# include <vector>

namespace coreutils {
   
   ///
   /// Use the ZString object when advanced parsing algorithms are required to simplify
   /// parsing. ZString is not a backing store and requires that any referenced buffer
   /// or objects are retained throughout the life of the object. Additionally, ZString
   /// is non-destructive to its underlying references.
   ///
   /// ZString provides several methods to reference and parse the content. First method
   /// is split(ZString delimiter) which will return a vector of ZString which contains
   /// references to the parts of the string split by the provided delimiter. The delimiter
   /// portion is omitted from the results.
   ///
   /// Second method involves a cursor which is a pointer to data contained within the
   /// ZString and is used to point to the current parsing point. Several methods are
   /// provided to advance through the parsing based upon content and rule checks.
   ///
   /// During the parsing process you can retrieve the parsed and unparsed sections of
   /// the ZString as ZStrings.
   ///
   /// You can stream the ZString to an output stream using the << operator and the entire
   /// contents of the ZString will be output regardless of parsing activity.
   ///
   
   class ZString {
      
    public:
      ///
      /// Consructor providing an empty ZString.
      ///
      
      ZString();
      
      ///
      /// Constructor wrapping a null terminated buffer to a ZString.
      ///
      
      ZString(const char *data);
      
      ///
      /// Consructor providing the initial setup of the ZString object.
      ///
      
      ZString(char *data, size_t length);
      
      ///
      ///
      ///
      
      ZString(const char *data, size_t length);
      
      ZString(unsigned char *data, size_t length);
      
      ///
      ///
      ///
      
      ZString(const ZString &zstring);
      
      ZString(const unsigned char *data, size_t length);
      
      ///
      /// Consructor providing a copy of a ZString.
      ///
      
      ZString(std::string &string);
      
      ///
      /// Consructor from a string.
      ///
      
      //      ZString(std::string string);
      
      ///
      /// Destructor for the ZString.
      ///
      
      virtual ~ZString();
      
      ///
      /// A friend method used to write the value of the ZString
      /// to an ostream using the << syntax.
      ///
      
      friend std::ostream &operator<<(std::ostream &os, const ZString &zstring);
      friend std::ostream &operator<<(std::ostream &os, const std::string &string);
      friend std::ostream &operator+(std::ostream &os, const ZString &zstring);
      friend std::ostream &operator+(std::ostream &os, const char *value);
      
      ///
      /// A friend method used to write the value of the ZString
      /// to an ostream using the << syntax.
      ///

      ///
      /// The < operator is used to compare values if ZString is used in std::map.
      ///
      
      bool operator<(const ZString &valuex) const;
      
      ///
      ///
      ///
      
      bool operator>(const ZString &valuex) const;
      bool operator<=(const ZString &valuex) const;
      bool operator>=(const ZString &valuex) const;
      bool operator==(const ZString valuex);
      bool operator!=(const ZString valuex) const;
      bool operator!=(const char *valuex) const;
      
      ///
      /// Return a vector of ZString objects which contain the parts established
      /// by using the split method and passing a delimiter value.
      ///
      
      std::vector<ZString> &getList();
      
      ///
      /// Return the integer value of the ZString from the cursor to the first
      /// non-numeric character.
      ///
      
      int asInteger();
      
      ///
      /// Return the floating point  value of the ZString from the cursor to the first
      /// non-numeric character.
      ///
      
      double asDouble();
      
      ///
      ///
      ///
      
      int incrementCursor(int length);
      
      ///
      /// Use the push method to push the current cursor pointer to a stack.
      ///
      
      void push();
      
      ///
      /// Use the pop method to pop a previously pushed cursor pointer from the
      /// cursor stack. The cursor will point to the same location in the
      /// ZString where the cursor was pushed.
      ///
      
      void pop();
      
      ///
      /// Return the value of the ZString from the cursor to the end.
      ///
      
      std::string str();
      
      ///
      /// Return the current value of the ZString as a string of
      /// specified length.
      ///
      
      std::string str(int len);
      
      ///
      ///
      ///
      
      char *c_str();
      
      ///
      ///
      ///
      
      ZString substring(int start);
      
      ///
      ///
      ///
      
      ZString substring(int start, int len);
      
      ///
      ///
      ///
      
      std::vector<ZString> &split(ZString &delimiter, size_t maxSize = 0);
      
      ///
      ///
      ///
      
      std::vector<ZString> &split(std::string delimiter, size_t maxSize = 0);

      ///
      /// If ZString cursor is currently pointing to a character in the include
      /// string then return true.
      ///
      
      bool ifNextInclude(ZString include);
      
      ///
      /// Use getTokenInclude with a list of character to allow the forwarding
      /// of the cursor through the data until a character that is not in the
      /// include string is not encountered in the ZString data.
      ///
      
      ZString getTokenInclude(const char *include);
      
      ///
      ///
      ///
      
      ZString getTokenExclude(const char *exclude);
      
      ///
      ///
      ///
      
      ZString getTokenExclude(std::string exclude);
      
      ///
      /// If the cursor is over a container character then a call to this method
      /// will return the contents of the container. The cursor will remain at
      /// the position following the container.
      ///
      
      ZString getContainer();
      
      ///
      /// Use the [] operator to retrieve values delimited by the split method.
      ///
      
      ZString &operator[](int index);
      
      ///
      /// Return true if the ZString cursor is at the end of the data.
      ///
      
      bool eod();

      ///
      /// Go to the end of data.
      ///
      /// Return number of bytes the cursor was moved. 
      ///

      int goeod();
      
      ///
      ///
      ///
      
      bool startsWith(const char *value);

      ///
      ///
      ///

      bool startsWithNumber();
      
      ///
      /// 
      ///

      int compare(ZString zstring);
      
      ///
      ///
      ///
      
      bool equals(const char *value);
      
      ///
      ///
      ///
      
      bool equals(char *value);
      
      ///
      ///
      ///
      
      bool equals(ZString &zstring);
      
      ///
      ///
      ///
      
      bool equals(std::string &string);
      
      ///
      /// Advance the cursor the length of the provided value if the value at
      /// the cursor position is equal to the value provided.
      ///
      
      bool ifNext(ZString value);
      
      ///
      ///
      ///
      
      bool ifNextIgnoreCase(ZString value);
      
      ///
      ///
      ///
      
      int ifEqualsCount(ZString &comparator);
      
      ///
      /// Advance the cursor through the ZString for each whitespace character
      /// encountered. 
      ///
      
      int skipWhitespace();

      ///
      ///
      ///

      int trimTrailingWhitespace();
      
      ///
      ///
      ///

      bool lineIsWhitespace();
      
      ///
      ///
      ///
      
      ZString goeol();

      ///
      ///
      ///
      
      ZString goeolwithContinuation();

      ///
      ///
      ///

      ZString trim();

      ///
      /// Return a block of data as a ZString from the cursor location for
      /// the number of bytes specified by size.
      ///
      
      ZString readBlock(size_t size);
      
      ///
      ///
      ///
      
      int find(ZString comparator);
      
      ///
      /// Return a block of data as a ZString from the cursor location for
      /// the number of bytes specified by size.
      ///
      
      char *getData() const;
      
      ///
      ///
      ///
      
      char *getCursor() const;
      
      ///
      ///
      ///
      
      void setCursor(char *cursor);
      
      ///
      /// Return the length of the ZString.
      ///
      
      size_t getLength() const;
      
      ///
      /// Set this ZString to have the same data space as the ZString pointer
      /// passed into the method.
      ///
      
      void setZString(ZString zstring);
      
      ///
      /// Use the parsed method to return a ZString that represents the portion
      /// ZString that has been parsed. The returned ZString represents the
      /// portion of the ZString from the data pointer to the cursor.
      ///
      
      ZString parsed();
      
      ///
      ///
      ///
      
      ZString unparsed();

      ///
      /// Set the ZString cursor to the end of the ZString.
      ///

      int setParsed();
      
      ///
      ///
      ///
      
      void reset();
      
      ///
      ///
      ///
      
      char charAt(int index);
      
      ///
      /// Retrurns true if the end of the ZString ends with CRLF. Does not
      /// Affect cursor position unless cursor is beyond the length of the line
      /// after trimming.
      ///
      
      bool trimCRLF();

      ///
      /// Returns the character at the cursor and returns. Cursor is not changed.
      ///

      char getChar();
      
      ///
      /// Returns the character at the cursor and advances the cursor one
      /// position until end of data.
      ///
      
      char nextChar();

      ///
      ///
      ///

      bool boolValue();

      ///
      ///
      ///

      ZString removeTrailingZeros();

      ///
      /// Returns the number of line termination characters + 1 based upon
      /// the cursor position.
      ///

      int getLineNumberAtCursor();

      ///
      /// Move the cursor to the beginning of a line or to the beginning of
      /// the ZString.
      ///

      void moveBackToLineStart();
            
    protected:
      char *data = NULL;
      char *cursor = NULL;
      size_t length = 0;
      char *cdata = NULL;
      std::vector<ZString> list;
      
    private:
      std::stack<char *> stack;
      bool isCharacter(char ch, ZString include);
   };
   
}

#endif
