#include "ZString.h"
#include "Log.h"

namespace coreutils {

   std::ostream& operator<<(std::ostream& os, const ZString &zstring) {
      for(int ix = 0; ix < zstring.length; ++ix) {
         os << zstring.data[ix];
      }
      return os;
   }

   std::ostream& operator<<(std::ostream& os, const std::string &string) {
      os << string;
      return os;
   }

   std::ostream& operator+(std::ostream& os, const ZString &zstring) {
      os << zstring;
      return os;
   }

   ZString::ZString() {
      data = NULL;
      length = 0;
      cursor = data;
   }

   ZString::ZString(const char *data) : data((char *)data), length(strlen(data)), cursor((char *)data) {}

   ZString::ZString(char *data, size_t length) : data(data), length(length), cursor(data) {}

   ZString::ZString(const char *data, size_t length) : data((char *)data), length(length), cursor((char *)data) {}

   ZString::ZString(const ZString &zstring) {
      data = zstring.data;
      length = zstring.length;
      cursor = zstring.cursor;
//      Log(LOG_DEBUG_2) << "ZString Copy Constructor: ";
   }

   std::vector<ZString> &ZString::getList() {
      return list;
   }

   int ZString::asInteger() {
      std::stringstream temp(std::string(data, length));
      int tempInt = 0;
      temp >> tempInt;
      return tempInt;
   }
   
   std::string ZString::str() {
      return std::string(data, length);
   }
   
   std::string ZString::str(int len) {
      return std::string(data, len);
   }
   
   std::vector<ZString> &ZString::split(std::string delimiter, size_t maxSize) {
      coreutils::ZString zDelimiter((char *)delimiter.c_str(), delimiter.size());
      return split(zDelimiter, maxSize);
   }
   
   std::vector<ZString> &ZString::split(ZString &delimiter, size_t maxSize) {
      list.clear();
      if(length == 0) {
	 list.push_back(ZString(""));
	 return list;
      }
      
      char *end = data + length;
      char *pos = cursor;
      
      while(pos < end) {
         if(strncmp(pos, delimiter.getData(), delimiter.getLength()) == 0) {
	    list.push_back(ZString(cursor, pos - cursor));
	    cursor = pos + delimiter.getLength();
	    pos = cursor;
	 }
	 else {
	    ++pos;
	 }
      }
      list.push_back(ZString(cursor, pos - cursor));
      cursor = pos;
      return list;
   }
   
   ZString ZString::getTokenInclude(const char *include) {
      char *start = cursor;
      int len = strcspn(cursor, include);
      cursor += len;
      return ZString(start, len);
   }
   
   ZString ZString::getTokenExclude(const char *exclude) {
      char *start = cursor;
      int len = strspn(cursor, exclude);
      cursor += len;
      return ZString(start, len);
   }
   
   ZString ZString::getTokenExclude(std::string exclude) {
      return getTokenExclude(exclude.c_str());
   }
   
   ZString &ZString::operator[](int index) {
      return list[index];
   }
   
   bool ZString::eod() {
      return cursor >= data + length;
   }
   
   bool ZString::equals(const char *value) {
      if(strlen(value) != length)
	return false;
      return strncmp(data, value, length) == 0;
   }
   
   bool ZString::equals(char *value) {
      if(strlen(value) != length)
	return false;
      return strncmp(data, value, length) == 0;
   }
   
   bool ZString::equals(ZString &zstring) {
      if(zstring.getLength() != getLength())
	return false;
      return strncmp(data, zstring.getData(), getLength()) == 0;
   }
   
   bool ZString::equals(std::string &string) {
      return string == std::string(data, length);
   }
   
   bool ZString::ifNext(const char *value) {
      bool test = (strncmp(cursor, value, strlen(value)) == 0);      
      if(test)
        cursor += strlen(value);
      return test;
   }
   
   int ZString::skipWhitespace() {
      int len = strspn(cursor, " \t");
      cursor += len;
      return len;
   }
   
   ZString ZString::goeol() {
      char* temp = cursor;
      cursor += strspn(cursor, "\r\n");
      return ZString(temp, cursor-- - temp);
   }
   
   ZString ZString::readBlock(size_t size) {
      char *temp = cursor;
      cursor += size;
      return ZString(temp, size);
   }
   
   char* ZString::getData() {
      return data;
   }
   
   size_t ZString::getLength() {
      return length; 
   }
   
   void ZString::setZString(ZString zstring) {
      data = zstring.getData();
      length = zstring.getLength();      
      cursor = data;
   }
   
}
