// ==========================================================================
// Author:  Yee Hsu
// Date:    8/5/2005
// File:    String.cpp
//
// Desc:    My own attempt to write a string class. String class is an
//          object of char* arrays and performs similarities to the "string"
//          type. Class overloads several operators to perfrom things such
//          as concatenations, copies, and comparisons.
// ==========================================================================

#include <iostream.h>
#include "String.h"

// ================================================================
// Description:
//      Implementation of class Node. Here is the file that
//      implements all the constructors, destructor, ADT member
//      functions, friend functions, overloaded functions, etc.
// ================================================================


// ==========================================================================
// Identifier:  Node()
//
// Description: Node Constructor
//              Initialize default fields
// ==========================================================================

Node::Node()
{
    this->ch = '\0';
    this->next = NULL;
}

// ================================================================
// Default copy constructor
// ================================================================

Node::Node(const Node &n)
{
    this->ch = n.ch;
    this->next = n.next;
}

// ================================================================
// Default destructor
// ================================================================

Node::~Node()
{
    this->ch = '\0';
    this->next = NULL;
}

// ================================================================
// Description:
//      Implementation of class String. Here is the file that
//      implements all the constructors, destructor, ADT member
//      functions, friend functions, overloaded functions, etc.
// ================================================================

// ================================================================
// Default constructor
// ================================================================

String::String() : head(NULL) {}

// ================================================================
// Overloaded constructor
// ================================================================

String::String(const char *str)
{
    if (*str == '\0')
        head = NULL;
    else
    {
        // copy the head node
        head = NULL;
        head = new Node;
        head->ch = *str;
        str++;

        // copy the rest of the list
        while (*str != '\0')
        {
            Insert(*str);
            str++;
        }
    }
}

// ================================================================
// Default copy constructor
// ================================================================

String::String(const String &s)
{
    if (s.head == NULL)
        head = NULL;
    else
    {
        // copy the head node
        head = new Node;
        head->ch = s.head->ch;

        pNode newptr = head;
        pNode oldptr = s.head->next;

        // copy the rest of the list
        while (oldptr != NULL)
        {
            newptr->next = new Node;
            newptr = newptr->next;
            newptr->ch = oldptr->ch;
            oldptr = oldptr->next;
        }
        newptr->next = NULL;
    }
}

// ================================================================
// Default destructor
// ================================================================

String::~String()
{
    pNode curr = head;

    while (curr != NULL)
    {
        head = head->next;
        delete curr;
        curr = head;
    }
}

// ================================================================
// Overloaded assignment = operator for character array
// ================================================================

String& String::operator =(const char *str)
{
    this->~String();

    if (*str == '\0')
        head = NULL;
    else
    {
        // copy the head node
        head = new Node;
        head->ch = *str;
        str++;

        // copy the rest of the list
        while (*str != '\0')
        {
            Insert(*str);
            str++;
        }
    }
    return *this;
}

// ================================================================
// Overloaded assignment = operator
// ================================================================

String& String::operator =(const String &s)
{
    if (this != &s)
    {
        this->~String();

        if (s.head == NULL)
            head = NULL;
        else
        {
            // copy the head node
            head = new Node;
            head->ch = s.head->ch;

            pNode newptr = head;
            pNode oldptr = s.head->next;

            // copy the rest of the list
            while (oldptr != NULL)
            {
                newptr->next = new Node;
                newptr = newptr->next;
                newptr->ch = oldptr->ch;
                oldptr = oldptr->next;
            }
            newptr->next = NULL;
        }
    }
    return *this;
}

// ================================================================
// Overloaded operation + operator
// ================================================================

String String::operator +(const String &s)
{
    String ss = *this;
        pNode curr = s.head;

    while (curr != NULL)
    {
        ss.Insert(curr->ch);
        curr = curr->next;
    }
    return ss;
}

// ================================================================
// Overloaded operation += operator
// ================================================================

String& String::operator +=(const String &s)
{
    *this = *this + s;
    return *this;
}

// ================================================================
// Overloaded relational == operator
// ================================================================

bool String::operator ==(const String &s)
{
    bool bSame = false;
    pNode curr1 = head;
    pNode curr2 = s.head;

    if (Length(*this) == Length(s))
    {
        while (curr1 != NULL)
        {
            bSame = false;

            if (curr1->ch == curr2->ch)
            {
                bSame = true;
                curr1 = curr1->next;
                curr2 = curr2->next;
            }
            else
                break;
        }
    }
    return bSame;
}

// ================================================================
// Overloaded relational != operator
// ================================================================

bool String::operator !=(const String &s)
{
    return !(*this == s);
}

// ==========================================================================
// Identifier:  Insert()
//
// Description: Inserts the character into the String object
// ==========================================================================

void String::Insert(const char ch)
{
    pNode temp = new Node;
    temp->ch = ch;
    temp->next = NULL;

    if (head == NULL)
        head = temp;
    else
    {
        pNode curr = head;

        while (curr->next != NULL)
            curr = curr->next;

        curr->next = temp;
    }
}

// ==========================================================================
// Identifier:  Length()
//
// Description: Gets the length of the String object
// ==========================================================================

int Length(const String &s)
{
    int count = 0;
    pNode curr = s.head;

    while (curr != NULL)
    {
        count++;
        curr = curr->next;
    }
    return count;
}

// ================================================================
// Overloaded operation ordinary + operator
// ================================================================

String operator +(const char *str, const String &s)
{
    String ss = str;
    return ss + s;
}

// ================================================================
// Overloaded friend stream >> operator
// ================================================================

istream& operator>>(istream &in, String &s)
{
    char ch;

    s.~String();

    while (in.peek() != '\n')
    {
        ch = in.get();
        s.Insert(ch);
    }
    return in;
}

// ================================================================
// Overloaded friend stream << operator
// ================================================================

ostream& operator<<(ostream &out, const String &s)
{
    pNode curr = s.head;

    while (curr != NULL)
    {
        out<<curr->ch;
        curr = curr->next;
    }
    return out;
}