// *****************************************************
// *                                                   *
// *   string.C                                        *
// *                                                   *
// *   Implementation for a string class               *
// *                                                   *
// *   Written 6/16/98 by Jason Zych                   *
// *    Altered 22 March 1999 -- op>> added            *
// *                                                   *
// *****************************************************

#include <string.h> 
#include "string.h"
#include "asserts.h"

 
// String
//    - default constructor
//    - parameters : initString - a pointer to a character array 
//    - initializes object to the string stored in the character array
String::String(char* initString) 
{
    if (initString==NULL)
    {
        stringLength = 0; 
        stringArray = new char[1];  
        stringArray[0]='\0';
    }
    else
    {
        stringLength = strlen(initString); 
        stringArray = new char[stringLength+1];
        for (int i=0; i <= stringLength; i++)
            stringArray[i] = initString[i];
    }
}


 
// String
//    - copy constructor
//    - parameters : origVal - previously allocated String object
//    - initializes object to be a copy of origVal
String::String(const String& origVal)
{
    stringLength = origVal.stringLength; 
    stringArray = new char[stringLength+1]; 
    for (int i=0; i <= stringLength; i++)
        stringArray[i] = origVal.stringArray[i];
}


 
// ~String
//    - destructor
//    - deletes dynamically allocated memory
String::~String()
{ 
   delete[] stringArray; 
}



// operator=
//    - parameters : origVal - previously allocated String object
//    - return value : reference to String object
//    - sets object to be a copy of origVal
String& String::operator=(const String& origVal)
{
   if (this!=&origVal) 
   {
      delete[] stringArray;

      stringLength=origVal.stringLength; 
      stringArray = new char[stringLength+1]; 
      for (int i=0; i <= stringLength; i++)
         stringArray[i] = origVal.stringArray[i];
   }
   return *this;
}


 
// operator[]
//    - parameters : index - the index into the String array
//    - return value : reference to a character object
//
char& String::operator[](int index) const
{
    Assert(((index >= 0) && (index <= stringLength)), 
             "Index to string out of bounds\n");
    return stringArray[index];
}

 
String String::Substring(int start, int len)
{
   Assert((start >= 0) && (start < stringLength), 
				"Start of substring not in string bounds.");  
   Assert((len >= 0), "Length of substring cannot be negative."); 
   if ((start + len - 1) > stringLength)
      len = stringLength - start + 1; 
 
   char* newStrArray = new char[len+1];   
   for (int i=start; i < (start + len); i++)
      newStrArray[i-start] = (*this)[i];
   newStrArray[i-start] = '\0';
   String temp(newStrArray); 
   delete[] newStrArray; 
   return temp; 
}

 
// Length
//    - return value : integer stringLengthgth of string
//    - returns the number of characters in the String
int String::Length() const
{ 
   return stringLength; 
} 
 


// operator+ 
//    - parameters : firstString - the first string in the conatenation
//                 : secondString - the second string in the concatenation
//    - return value : a String value 
//    - creates a new String formed by concatenating the two parameter
//           strings in the given order; returns this String
String operator+(const String& leftString, const String& rightString)
{
   int i;  // counter
   int firstLength = leftString.stringLength; 
   int newStringLength = leftString.stringLength + rightString.stringLength; 
   char* newStrArray = new char[newStringLength+1]; 
   for (i = 0; i < firstLength; i++)
      newStrArray[i] = leftString[i]; 
   for (i=firstLength; i<newStringLength; i++)
      newStrArray[i] = rightString[i-firstLength];  
   newStrArray[newStringLength] = '\0'; 
   String temp(newStrArray); 
   delete[] newStrArray; 
   return temp; 
}
 
 
// operator==
//    - parameters : leftString - the first of two strings being compared
//                 : rightString - the second of two string being compared
//    - return value : a boolean-valued integer
//    - returns 1 if strings are equal, 0 otherwise
int operator==(const String& leftString, const String& rightString) 
{
    return strcmp(leftString.stringArray, rightString.stringArray)==0;
}


// operator!=
//    - parameters : leftString - the first of two strings being compared
//                 : rightString - the second of two string being compared
//    - return value : a boolean-valued integer
//    - returns 1 if strings are not equal, 0 otherwise
int operator!= (const String& leftString, const String& rightString)
{
    return strcmp(leftString.stringArray, rightString.stringArray)!=0;
}


// operator<
//    - parameters : leftString - the first of two strings being compared
//                 : rightString - the second of two string being compared
//    - return value : a boolean-valued integer
//    - returns 1 if the first string comes before the second in
//         alphabetical order; 0 otherwise
int operator< (const String& leftString, const String& rightString)
{
    return strcmp(leftString.stringArray, rightString.stringArray)<0;
}



// operator>
//    - parameters : leftString - the first of two strings being compared
//                 : rightString - the second of two string being compared
//    - return value : a boolean-valued integer
//    - returns 1 if the first string comes after the second in
//         alphabetical order; 0 otherwise
int operator> (const String& leftString, const String& rightString)
{
    return strcmp(leftString.stringArray, rightString.stringArray) > 0;
}



// operator<<
//    - parameters : Out - an ostream reference
//                 : outputString - a String to write to output 
//    - return value : an ostream reference
//    - writes the given String to the given output stream
ostream & operator<<(ostream & Out, const String& outputString)
{
    Out << outputString.stringArray;
    return Out;
}
 

// operator>>
//    - parameters : In - an istream reference
//                 : inputString - a String to read from input 
//    - return value : an istream reference
//    - reads a String from the given input stream
istream& operator>>(istream& In, String& inputString)
{
   int sizeOfBuffer = 100;

   // technically, there is a better way to handle this than to
   //   assume a maximum size on the string, but for the moment,
   //   assuming a maximum size of 10000 elements is a pretty safe
   //   bet and we will allow it for simplicity's sake
   char* tempBuffer = new char[10000];   

   In >> tempBuffer; 

   // the actual String is now equal to the read-in character array
   inputString = String(tempBuffer);

   delete tempBuffer; 
   return In;
}
 
