/* String1.cpp */
#include <iostream>
#include <iomanip>
#include <new>               // C++ standard "new" operator
#include <cstring>           // strcpy and strcat prototypes
#include <cstdlib>           // exit prototype
#include "String1.h"

using namespace std;


// Private utility function called by constructors and operator=
void String::setString(const char *string2) {
  sPtr = new char[length + 1];    // allocate memory

  // if string2 is not a null pointer, copy contents
  if (string2 != 0) {
    strcpy(sPtr, string2);        // copy literal to object
  }
  // if string2 is a null pointer, make this an empty string
  else {
    sPtr[0] = '\0';               // empty string
  }
}



// Conversion/default constructor converts char * to String.
// NOT null pointer-safe!
String::String(const char *s /* = "" */) : length((s != 0) ? strlen(s) : 0) {
  cout << "Conversion constructor: " << s << '\n';
  setString(s);
}



// Copy constructor
String::String(const String &copy) : length(copy.length) {
  cout << "Copy constructor: " << copy.sPtr << '\n';
  setString(copy.sPtr);
}



// Destructor
String::~String() {
  cout << "Destructor: " << sPtr << '\n';
  delete[] sPtr;
}



// Overloaded = operator; avoid self assignment
const String& String::operator=(const String& right) {
  cout << "operator= called\n";
  if (&right != this) {      // avoid self assignment
    delete[] sPtr;
    length = right.length;
    setString(right.sPtr);
  }
  else {
    cout << "Attempted assignment of a String to itself\n";
  }

  return *this;              // enable cascaded assignments
}



// Concatenate right operand to this object and store in this object.
const String& String::operator+=(const String& right) {
  size_t newLength = length + right.length; // new length
  char *tempPtr = new char[newLength + 1];  // create memory
  strcpy(tempPtr, sPtr);
  strcpy(tempPtr + length, right.sPtr);
  delete[] sPtr;
  sPtr = tempPtr;                           // assign new array to sPtr
  length = newLength;                       // assign new length to length

  return *this;                             // enable cascaded calls
}



// Is this String empty?
bool String::operator!() const {
  return length == 0;
}



// Is this String equal to right String?
bool String::operator==(const String& right) const {
  return strcmp(sPtr, right.sPtr) == 0;
}



// Is this String less than right String?
bool String::operator<(const String& right) const {
  return strcmp(sPtr, right.sPtr) < 0;
}



// Return reference to character in String as lvalue
char& String::operator[](int subscript) {
  // test for subscript out of range
  if (subscript < 0 || subscript >= length) {
    cout << "Error: Subscript " << subscript << " out of range" << endl;
    exit(1);
  }

  return sPtr[subscript];         // creates lvalue
}



// Return reference to character in String as rvalue
const char& String::operator[](int subscript) const {
  // test for subscript out of range
  if (subscript < 0 || subscript >= length) {
    cout << "Error: Subscript " << subscript << " out of range" << endl;
    exit(1);
  }

  return sPtr[subscript];         // creates rvalue
}



// Return a substring beginning at index and
// of length subLength
String String::operator()(int index, int subLength) {
  // if index is out of range or substring length < 0,
  // return an empty String object
  if (index < 0 || index >= length || subLength < 0) {
    return "";               // converted to a String object automatically
  }

  // determine length of substring
  int len;
  if ((subLength == 0) || (index + subLength > length)) {
    len = length - index;
  }
  else {
    len = subLength;
  }

  // allocate temporary array for substring and
  // terminating null character
  char *tempPtr = new char[len + 1];

  // copy substring into char array and terminate string
  strncpy(tempPtr, &sPtr[index], len);
  tempPtr[len] = '\0';

  // create temporary String object containing the substring
  String tempString(tempPtr);
  delete[] tempPtr;          // delete temporary array

  return tempString;         // return copy of the temporary String
}



// Return string length
int String::getLength() const {
  return length;
}



// Overloaded output operator
ostream& operator<<(ostream& output, const String& s) {
  output << s.sPtr;
  return output;             // enable cascading

}



// Overloaded input operator
istream& operator>>(istream& input, String& s) {
  char temp[100];            // buffer to store input
  input >> setw(100) >> temp;
  s = temp;                  // use String class assignment operator
  return input;              // enable cascading
}
