/// \file   String.h
/// \author	Randall Knapp
/// \date   December 12, 2009 - 21:30
/// \par    &copy; Randall Knapp 2009-2010
/// \par    Email: randall\@randallknapp.com
/// \brief  Character string
#pragma once

#define R_USING_STL

#ifdef R_USING_STL
  // For tokenization
  #include <vector>
#endif

namespace R
{

  class String
  {
  public:
    // Constructors
    String(); ///< Default constructor
    String( const char* Str ); ///< String literal conversion constructor
    String( const String& Str ); ///< Copy constructor

    // Conversion constructors
    String( char Number ); ///< Char conversion constructor
    String( unsigned char Number ); ///< Unsigned char conversion constructor
    String( short Number ); ///< Short conversion constructor
    String( unsigned short Number ); ///< Unsigned short conversion constructor
    String( long Number ); ///< Long conversion constructor
    String( unsigned long Number ); ///< Unsigned long conversion constructor
    String( int Number ); ///< Int conversion constructor
    String( unsigned int Number ); ///< Unsigned int conversion constructor
    String( float Number ); ///< Float conversion constructor
    String( double Number ); ///< Double conversion constructor
    String( bool Value ); ///< Boolean conversion constructor ("true" or "false")

    /// Destructor
    ~String();

    // Operations
    String& operator=( const String& rhs ); ///< Assignment operator
    String operator+( const String& rhs ) const; ///< String concatenation
    String operator+( const char* rhs ) const; ///< String literal concatenation
    char& operator[]( int index ); ///< Character index operator
    String& operator+=( const String& rhs ); ///< Concat-Assign operator
    String& operator+=( const char* rhs ); ///< Concat-Assign string literal operator

    // Logical Operations
    bool operator==( const String& rhs ) const; ///< Logical equality (each character is the same)
    bool operator==( const char* rhs ) const; ///< Logical equality with string literal
    bool operator<( const String& rhs ) const; ///< Logical (alphabetical) less-than (previous to)
    bool operator>( const String& rhs ) const; ///< Logical (alphabetical) greater-than (after)

    // Methods
    void Clear(); ///< Erases the whole string
    int Length() const; ///< Number of characters
    bool IsEmpty() const; ///< Check if the string is an empty string
    String& MakeLower(); ///< Change all of the characters to lower case
    String ToLower() const; ///< Get a copy of this string with all lower case characters
    String& MakeUpper(); ///< Change all of the characters to upper case
    String ToUpper() const; ///< Get a copy of this string with all upper case characters
    String& MakeCapitalCase(); ///< Change the string so that each character after whitespace is upper case and all others are lowercase
    String ToCapitalCase() const; ///< Get a copy of the string such that each character after whitespace is upper case and all others are lowercase
    String& Reverse(); ///< Reverse the order of the characters in this string
    String GetReversed() const; ///< Get a copy of the string in reverse order
    String& DeleteChar( int Index ); ///< Delete a character by index
    String& Backspace(); ///< Delete a character from the end
    String SubString( int Start, int End ) const; ///< Get a substring
    const char* ToCString() const; ///< Convert this string to a c-style string

#ifdef R_USING_STL
    void GetTokens( const String& Delimiters, std::vector<String>& Out ) const; ///< Tokenize the string. Delimiters is a string of characters, any of which may separate tokens
#endif

  private:
    // Private Methods
    int StrLen( const char* Str ) const;
    void StrCopy( char* Dest, const char* Src ) const;
    void Allocate( int Size );
    void Free();
    void MakeEmpty();
    void MakeCharLower( char& c ) const;
    void MakeCharUpper( char& c ) const;
    char GetCharLower( char c ) const;
    char GetCharUpper( char c ) const;
    bool IsAlphaNumeric( char c ) const;
    
    // Initialize helpers
    void InitFromInt( int Number );
    void InitFromUnsignedInt( unsigned int Number );
    void InitFromStringLiteral( const char* c, int length );
    void InitFromString( const String& Str );

    // Private Data
    char* m_Data;
    int m_Length;
  };

}

inline R::String operator+( const char* str, const R::String& rhs ) { return R::String(str) + rhs; }
