#include "MString.h"
#include "Log.h"
#include <stdlib.h>
#include <iomanip>
#include <cstring>

namespace coreutils {

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

   MString::MString(const char *data) {
      setSize(strlen(data));
      memcpy(this->data, data, length);
      cursor = this->data;
   }

   MString::MString(char *data, size_t length) {
      setSize(length);
      memcpy(this->data, data, length);
      cursor = this->data;
   }

   MString::MString(const char *data, size_t length) {
      setSize(length);
      memcpy(this->data, data, length);
      cursor = this->data;
   }

   MString::MString(const MString &mstring) {
      setSize(mstring.length);
      memcpy(data, mstring.data, mstring.length);
      cursor = data;
//      Log(LOG_DEBUG_2) << "MString Copy Constructor: ";
   }

   MString::MString(ZString &zstring) {
      setSize(zstring.getLength());
      memcpy(data, zstring.getData(), zstring.getLength());
      cursor = data;
   }

   MString::MString(ZString zstring) {
      setSize(zstring.getLength());
      memcpy(data, zstring.getData(), zstring.getLength());
      cursor = data;
   }

   MString::MString(std::string data) {
      setSize(data.length());
      memcpy(this->data, (char *)data.c_str(), data.length());
      cursor = this->data;
   }

   MString::~MString() {
      if(data)
        free(data);
   }

   // MString& MString::operator=(coreutils::ZString& value) {
   //    if(*this == value)
	// return *this;
   //    int len = length;
   //    setSize(length + value.getLength());
   //    memcpy(data + len, value.getData(), value.getLength());
   //    return *this;
   // }

   // MString& MString::operator=(coreutils::ZString& value) {
   //    if(*this == value)
   //   	  return *this;
   //    int len = length;
   //    setSize(length + value.getLength());
   //    memcpy(data + len, value.getData(), value.getLength());
   //    return *this;
   // }

   MString& MString::operator=(coreutils::ZString &value) {
//      if(*this == value)
//     	  return *this;
      setSize(value.getLength());
      memcpy(data, value.getData(), value.getLength());
      length = value.getLength();
      return *this;
   }

   MString& MString::operator=(const char *value) {
      int len = strlen(value);
      setSize(len);
      memcpy(data, value, len);
      return *this;
   }

   MString& MString::operator=(char value) {
      int len = 1;
      setSize(1);
      *data = value;
      return *this;
   }

   MString& MString::operator<<(const char *value) {
      int temp = length;
      int len = strlen(value);
      setSize(len + length);
      memcpy(data + temp, value, len);
      return *this;
   }

   MString& MString::operator<<(const int value) {
      std::stringstream temp;
      temp << value;
      *this << temp.str();
      return *this;
   }

//   MString& MString::operator<<(coreutils::ZString &zstring) {
//      int temp = length;
//      int len = length + zstring.getLength();
//      setSize(len);
//      memcpy(data + temp, zstring.getData(), zstring.getLength());
//      return *this;
//   }

   MString& MString::operator<<(coreutils::ZString zstring) {
      int temp = length;
      int len = length + zstring.getLength();
      setSize(len);
      memcpy(data + temp, zstring.getData(), zstring.getLength());
      return *this;
   }

   MString& MString::operator<<(std::string value) {
      int temp = length;
      int len = length + value.length();
      setSize(len);
      memcpy(data + temp, value.c_str(), value.length());
      return *this;
   }

   void MString::insert(char ch, int offset) {
      setSize(length + 1); 
      for(int ix = length; ix >= offset; ix--) 
	getData()[ix + 1] = getData()[ix]; 
      data[offset] = ch;
   }
   
   void MString::insert(ZString &value, int offset) {
      setSize(length + value.getLength());
      for(int ix = length; ix >= offset; ix--) 
	getData()[ix + value.getLength()] = getData()[ix]; 
      std::memcpy(data + offset, value.getData(), value.getLength());
   }
   
   void MString::insert(std::string value, int offset) {
      setSize(length + value.size());
      for(int ix = length; ix >= offset; ix--) 
	getData()[ix + value.size()] = getData()[ix]; 
      std::memcpy(data + offset, value.c_str(), value.size());
   }
   
   void MString::replace(char ch, int offset) {
      
   }
   
   void MString::replace(ZString &value, int offset) {
      
   }
   
   void MString::replace(std::string value, int offset) {
   }
   
   void MString::remove(int offset, int length) {
//      (data + this->length) > (data + offset + length) ? length: length; // TODO: Need to calculate correct length.
      for(int ix = offset; ix < this->length; ix++) 
	getData()[ix] = getData()[ix + length]; 
      setSize(this->length - length);
   }
   
   MString& MString::write(char ch) {
      setSize(length + 1);
      *(data + length - 1) = ch;
      return *this;
   }

   MString& MString::write(ZString &value) {
      int len = length;
      setSize(length + value.getLength());
      memcpy(data + len, value.getData(), value.getLength());
      return *this;
   }

   void MString::setSize(int size) {
      int cursorOffset = cursor - data;
      int newBufferSize = ((size / 256) + 1) * 256;
      if(bufferSize != newBufferSize) {
	 bufferSize = newBufferSize;
	 data = (char *)realloc(data, bufferSize);
	 cursor = data + cursorOffset;
      }
      length = size;
   }

   int MString::offset() {
      return cursor - data;
   }


}
