/***************************************************************************
                          cstring.h  -  description
                             -------------------
    begin                : Fri Sep 21 2001
    copyright            : (C) 2001-2003 by Mathias Küster
    email                : mathen@users.berlios.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef CSTRING_H
#define CSTRING_H

/**
  *@author Mathias Küster
  *
  * Now that CStringList is a template class, lots of classes, starting
  * with CString, no longer need to inherit CObject or have a virtual
  * destructor, which should make creating and destroying them
  * slightly faster.
  *
  * The appending functions no longer start by making a copy of the data
  * and then appending that. Instead there is some pointer checking,
  * for handling appending (part of) a string to itself.
  *
  * Despite dclib being full of "inline" functions, IsEmpty() is not inline.
  *
  * CString s = "";
  * s.Data() == NULL;
  *
  * An empty CString generally contains a NULL pointer. NULL pointers usually
  * crash C library functions that take a "char *" parameter.
  *
  * CString has no idea what encoding the string is in, it's length is the
  * number of bytes which may well be more than the number of characters
  * for UTF-8. ToUpper() and ToLower() only handle ascii a-z -> A-Z.
  *
  * The main thing about CString is it does not having the implicit sharing
  * that the QT's QString and other classes, so it is not very efficient to
  * pass it around by value.
  */

#include <dclib/dcos.h>

class CString {
public:
	/** Constructs a null string.
	    This is a string that has not been assigned to anything, i.e. both the length and data pointer is 0.
	*/
	CString();
	/** Constructs a string that is a deep copy of sz, interpreted as a classic C string. If sz is 0, then a null string is created.
	*/
	CString( const char * sz );
	/** Constructs a string giving it a length of one character, assigning it the character ch.
	*/
	CString( const char ch );
	/** Constructs a string that is a deep copy of stringSrc.
	*/
	CString( const CString & stringSrc );
	/** Destroys the string and frees its buffer.
	*/
	~CString();

	/** */
	void Empty();
	/** */
	bool IsEmpty() const;
	/** */
	bool NotEmpty() const { return !IsEmpty(); }
	/**
	 * This is supposed to be faster than doing
	 *
	 * s.Left(other.Length()) == other
	 *
	 * because it avoids Left() which creates a copy.
	 *
	 * In QT4 a null QString does not start with an empty QString.
	 * However in dclib an empty CString is always null.
	 * Therefore if other is empty StartsWith always returns true
	 * even if this CString is also empty.
	 */
	bool StartsWith( const CString & other ) const;
	/** */
	bool StartsWith( const char * other, long len ) const;
	/** */
	inline CString& Set( const char * sz, long nLength ) { set(sz,nLength); return *this; }

	/** */
	long Find( const char ch, long nStart = 0 ) const;
	/** */
	long Find( const char * sz, long nStart = 0, bool cs = true ) const;
	/** */
	long Find( const CString & string, long nStart = 0, bool cs = true ) const;
	/** */
	long FindCase( const char * sz, long nStart = 0 ) const;
	/** */
	long FindCase( const CString & string, long nStart = 0 ) const;
	/** */
	long FindRev( char ch, long nStart = -1 ) const;
	/** */
	long FindRev( const CString & string ) const;

	/** */
	void Append( const char ch );
	/** */
	inline void Append( const char * sz ) { add(sz); }
	/** */
	inline void Append( const CString & string ) { add(string.Data(),string.Length()); }

	/** */
	inline CString Left( long nCount ) const { return Mid(0,nCount); }
	/** */
	inline CString Right( long nCount ) const { return Mid(Length()-nCount,nCount); };
	/** */
	CString Mid( long nFirst, long nCount = -1 ) const;
	/** */
	CString Section( const char sep, int start, int end ) const;

	/** */
	CString RightJustify( long nNewLength, char chFill = ' ', bool truncate = false );

	/** */
	CString ToUpper() const;
	/** */
	CString ToLower() const;

	/** */
	CString Replace( CString src, CString string ) const;
	/**
	 * Replaces all occurences of 'before' in the string
	 * with 'after'.
	 *
	 * Although any normal string replace function would
	 * return a reference to itself by returning *this,
	 * CString::Swap() does not.
	 */
	void Swap( const char before, const char after );

	/**
	 * These all used to be called setNum but since
	 * they didn't (did not modify the string), they just make
	 * a new string and return it, they have been made static
	 * and renamed for consistency with QString.
	 */
	static CString number( const int n );
	/** */
	static CString number( const unsigned int n );
	/** */
	static CString number( const long n );
	/** */
	static CString number( const unsigned long n );
	/** */
	static CString number( const long long n );
	/** */
	static CString number( const ulonglong n );
	/** */
	static CString number( const double n, const int p );
	/** */
	ulonglong asULL( int base = 10 ) const;
	/** */
	unsigned int asUINT( int base = 10 ) const;
	/** */
	unsigned long asULONG( int base = 10 ) const;
	/** */
	int asINT( int base = 10 ) const;
	/** */
	long asLONG( int base = 10 ) const;
	/** */
	long long asLONGLONG( int base = 10 ) const;
	/** */
	double asDOUBLE() const;

	/** */
	unsigned char GetHash( long value = 0 ) const;

	/** */
	inline CString& operator += ( const char ch ) { Append(ch); return *this; };
	/** */
	inline CString& operator += ( const char * sz ) { add(sz); return *this; };
	/** */
	inline CString& operator += ( const CString & string ) { add(string.Data(),string.Length()); return *this; };


	/** */
	inline CString & operator = ( const char * sz ) { set(sz); return *this; };
	/** */
	inline CString & operator = ( const CString & string ) { set(string.Data(),string.Length()); return *this; };

	/** */
	inline char * Data() const { return m_szBuffer; }
	/** */
	inline long Length() const { return m_nStringLength; }

	/**
	 * Returns 0 if strings are equal, <0 if other is less than this, >0 if other is greater than this.
	 * So essentially it's just strcoll (which uses current locale).
	 */
	int Compare ( const CString & other ) const;
	/** */
	int Compare ( const char * other ) const;
	
private:
	/** */
	long m_nStringLength;
	/** */
	long m_nBufferSize;
	/** */
	char * m_szBuffer;

	/** */
	void set( const char * sz, long nLength = -1 );
	/** */
	void add( const char * sz, long nLength = -1 );
	/**
	 * This should never have been public unless you actually
	 * want a function for leaking memory.
	 */
	void Init();
	
	/**
	 * For private use, to create a CString from an existing buffer.
	 */
	CString( char * buffer, long length, long bufsize );
};

/** */
bool operator == ( const CString & string1, const CString & string2 );
/** */
bool operator == ( const char * sz, const CString & string );
/** */
bool operator == ( const CString & string, const char * sz );
/** */
bool operator != ( const CString & string1, const CString & string2 );
/** */
bool operator != ( const char * sz, const CString & string );
/** */
bool operator != ( const CString & string1, const char * sz );
/** */
inline CString operator + ( const CString & string1, const CString & string2 ) { CString tmp(string1); tmp.Append(string2); return tmp; }
/** */
inline CString operator + ( const char * sz, const CString & string ) { CString tmp(sz); return (tmp+string); }

/** Returns true if lhs is less than rhs, false if equal or greater than */
inline bool operator < ( const CString & lhs, const CString & rhs ) { return (lhs.Compare(rhs) < 0); }
/** Returns true if lhs is less than rhs, false if equal or greater than */
inline bool operator < ( const CString & lhs, const char * rhs ) { return (lhs.Compare(rhs) < 0); }
/** Returns true if lhs is less than rhs, false if equal or greater than */
inline bool operator < ( const char * lhs, const CString & rhs ) { return (rhs.Compare(lhs) > 0); }

/** Returns true if lhs is less than or equal to rhs, false if greater than */
inline bool operator <= ( const CString & lhs, const CString & rhs ) { return (lhs.Compare(rhs) <= 0); }
/** Returns true if lhs is less than or equal to rhs, false if greater than */
inline bool operator <= ( const CString & lhs, const char * rhs ) { return (lhs.Compare(rhs) <= 0); }
/** Returns true if lhs is less than or equal to rhs, false if greater than */
inline bool operator <= ( const char * lhs, const CString & rhs ) { return (rhs.Compare(lhs) >= 0); }

/** Returns true if lhs is greater than rhs, false if equal or less than */
inline bool operator > ( const CString & lhs, const CString & rhs ) { return (lhs.Compare(rhs) > 0); }
/** Returns true if lhs is greater than rhs, false if equal or less than */
inline bool operator > ( const CString & lhs, const char * rhs ) { return (lhs.Compare(rhs) > 0); }
/** Returns true if lhs is greater than rhs, false if equal or less than */
inline bool operator > ( const char * lhs, const CString & rhs ) { return (rhs.Compare(lhs) < 0); }

/** Returns true if lhs is greater than or equal to rhs, false if less than */
inline bool operator >= ( const CString & lhs, const CString & rhs ) { return (lhs.Compare(rhs) >= 0); }
/** Returns true if lhs is greater than or equal to rhs, false if less than */
inline bool operator >= ( const CString & lhs, const char * rhs ) { return (lhs.Compare(rhs) >= 0); }
/** Returns true if lhs is greater than or equal to rhs, false if less than */
inline bool operator >= ( const char * lhs, const CString & rhs ) { return (rhs.Compare(lhs) <= 0); }

#endif
