/***************************************************************************
 *   Copyright (C) 2008 by Peter Eschright                                 *
 *   petereschright@gmail.com                                              *
 *                                                                         *
 *   This source code is presented for informational purposes only.        *
 *   Please contact the author for permision for use.                      *
 **************************************************************************/

// /////////////////////////////////////////////////////////////
//
// File name: my_string.cpp
// File description: implementation of the my_string class
//
// /////////////////////////////////////////////////////////////

#include "my_string.h"

// ///////////////////////
//  constructors
// ///////////////////////

my_string::my_string(){
   strdata = new char[4];
   strdata[0] = 0; 
   mem_size = 4;
   length = 0;
}



my_string::my_string(const char *text_str){
   length = strlen(text_str);
   mem_size = length + 1;
   if(mem_size < 4) mem_size = 4;
   strdata = new char[mem_size];
   strcpy(strdata,text_str);
}



my_string::my_string(const my_string &str){
   if(str.length){
      length = str.length;
      mem_size = length + 1;
      if(mem_size < 4) mem_size = 4;
      strdata = new char[mem_size];
      strcpy(strdata,str.strdata);
   }
   else{
      strdata = new char[4];
      strdata[0] = 0; 
      mem_size = 4;
      length = 0;
   }
}




// destructor
my_string::~my_string(){
   if(strdata){ delete strdata; }
   strdata = 0;
   mem_size = 0;
   length = 0;
}




// clear string and release memory
void my_string::clear(){
   if(strdata){ delete strdata; }
   strdata = new char[4];
   strdata[0] = 0; 
   mem_size = 4;
   length = 0;
}




// //////////////////////////////////////////////
//
//  Operators
//
// //////////////////////////////////////////////

// ///////////////////////////////
// assignment
// ///////////////////////////////

my_string & my_string::operator=(const my_string &cpystring){
   // check for self assignment
   if(this == &cpystring){return(*this);} 
   
   if(cpystring.length){
      length = cpystring.length;
      mem_size = length + 1;
      if(mem_size < 4) mem_size = 4;
      if(strdata){ delete strdata; }
      strdata = new char[mem_size];
      strcpy(strdata,cpystring.strdata);
   }
   else{
      clear();
   }
   return(*this);
}



my_string & my_string::operator=(const char *ascii_text){
    if(strlen(ascii_text)){
      length = strlen(ascii_text);
      mem_size = length + 1;
      if(mem_size < 4) mem_size = 4;
      if(strdata){ delete strdata; }
      strdata = new char[mem_size];
      strcpy(strdata,ascii_text);
   }
   else{
      clear();
   }
   return(*this);
}




// ////////////////////////////////
//  Input and Output
// ////////////////////////////////

// output string to stream
ostream &operator<<(ostream & output, const my_string & str){
   output << str.strdata;
   return output;
}



// read line of input like below
istream &operator>>(istream & input, my_string & str){
   str.getline(input);
   return(input);
}



// read up to 255 char in a line
// return length of input
int my_string::getline(istream & input, char delim){
   clear();
   strdata = new char[256];
   mem_size = 256;
   input.getline(strdata,256,delim);
   length = strlen(strdata);
   return(length);
}


 

// ////////////////////////////////
// character access
// ////////////////////////////////

char &my_string::operator[](int i){
   // returned if [] index out of range
   // static char bad_char;
   // fix bad indexes
   if(i >= 0){
      if(i > length){
         bad_char = 0;
         return(bad_char);
      }
      // else ok
      return(strdata[i]);
   }
   // else no good
   bad_char = 0;
   return(bad_char);
}




// ////////////////////////////////////////
// logical and comparison operators
// ////////////////////////////////////////

bool my_string::operator==(const my_string &str) const{
   if(strcmp(strdata,str.strdata) == 0)
      return(true);
   return(false);
}



bool my_string::operator<(const my_string &str) const{
   if(strcmp(strdata,str.strdata) < 0)
      return(true);
   return(false);
}



bool my_string::operator>(const my_string &str) const{
   if(strcmp(strdata,str.strdata) > 0)
      return(true);
   return(false);
}



bool my_string::operator!=(const my_string &str) const{
   if(strcmp(strdata,str.strdata) != 0)
      return(true);
   return(false);
}



bool my_string::operator<=(const my_string &str) const{
   if(strcmp(strdata,str.strdata) <= 0)
      return(true);
   return(false);
}



bool my_string::operator>=(const my_string &str) const{
   if(strcmp(strdata,str.strdata) >= 0)
      return(true);
   return(false);
}




bool my_string::operator==(const char *str) const{
   if(strcmp(strdata,str) == 0)
      return(true);
   return(false);
}



bool my_string::operator!=(const char *str) const{
   if(strcmp(strdata,str) != 0)
      return(true);
   return(false);
}



bool my_string::operator<(const char *str) const{
   if(strcmp(strdata,str) < 0)
      return(true);
   return(false);
}



bool my_string::operator<=(const char *str) const{
   if(strcmp(strdata,str) <= 0)
      return(true);
   return(false);
}



bool my_string::operator>(const char *str) const{
   if(strcmp(strdata,str) > 0)
      return(true);
   return(false);
}



bool my_string::operator>=(const char *str) const{
   if(strcmp(strdata,str) >= 0)
      return(true);
   return(false);
}



bool operator==(const char *str1, const my_string &str2){
   if(strcmp(str1,str2.strdata) == 0)
      return(true);
   return(false);
}



bool operator!=(const char *str1, const my_string &str2){
   if(strcmp(str1,str2.strdata) != 0)
      return(true);
   return(false);
}



bool operator<(const char *str1, const my_string &str2){
   if(strcmp(str1,str2.strdata) < 0)
      return(true);
   return(false);
}



bool operator<=(const char *str1, const my_string &str2){
   if(strcmp(str1,str2.strdata) <= 0)
      return(true);
   return(false);
}



bool operator>(const char *str1, const my_string &str2){
   if(strcmp(str1,str2.strdata) > 0)
      return(true);
   return(false);
}



bool operator>=(const char *str1, const my_string &str2){
   if(strcmp(str1,str2.strdata) >= 0)
      return(true);
   return(false);
}




// ///////////////////////////////
//  concatenation
// ///////////////////////////////

// in place
my_string &my_string::operator+=(const my_string &cpystring){
   if(strdata){ // str has contents do concatenation
      length = length + cpystring.length;
      mem_size = length + 1;
      char *temp = strdata; 
      strdata = new char[mem_size];
      strcpy(strdata,temp);
      strcat(strdata,cpystring.strdata);
   }
   else{ // just assign string
      if(this == &cpystring){return(*this);} // check for self assignment
      length = cpystring.length;
      mem_size = length + 1;
      strdata = new char[mem_size];
      strcpy(strdata,cpystring.strdata);
   }
   return(*this);
}



my_string &my_string::operator+=(const char *str){
   if(strdata){ // str has contents do concatenation
      length = length + strlen(str);
      mem_size = length + 1;
      char *temp = strdata; 
      strdata = new char[mem_size];
      strcpy(strdata,temp);
      strcat(strdata,str);
   }
   else{ // just assign string
      length = strlen(str);
      mem_size = length + 1;
      strdata = new char[mem_size];
      strcpy(strdata,str);
   }
   return(*this);
}




// general
my_string my_string::operator+(const my_string &cpystring){
   my_string temp(*this);
   temp += cpystring;
   return(temp);
}



my_string my_string::operator+(const char *str){
   my_string temp(*this);
   temp += str;
   return(temp);
}





// ///////////////////////////////////////////
// reformating and truncation
// ///////////////////////////////////////////

// remove preceding and trailing whitespace
bool my_string::trim(){
   bool b;
   b = ltrim();
   b = rtrim() || b;
   return(b);
}



// remove preceding whitespace
bool my_string::ltrim(){
   if(isspace(strdata[0])){
      char *pos;
      pos = strdata;
      while(*pos && isspace(*pos)) ++pos;
      strcpy(strdata,pos);
      length = length - static_cast<int>(pos - strdata);
      return(true);
   }
   return(false);
}



// remove trailing whitespace
bool my_string::rtrim(){
   if((length > 1) && isspace(strdata[(length - 1)])){
      while( (length > 1) && isspace(strdata[(length - 1)]) ) --length;
      strdata[length] = 0;
      return(true); 
   }
   return(false);
}



// remove trailing newline if found
bool my_string::chomp(){
   if((length > 1) && ( strdata[(length - 1)] == '\n')   ){
      --length;
      strdata[(length - 1)] = 0;
      return(true);
   }
   return(false);
}




// truncate to specified pos
// if pos is after end of string
// string is unchanged
// return length after truncation
int my_string::truncate(int pos){
   if(pos >= 0){
      if(pos < length){
         length = pos;
         strdata[length] = 0;
      }
   }
   return(length);
}