//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * 文字列ヘッダ
 * @author Junpee
 */

#ifndef STRING_H_
#define STRING_H_

namespace Lamp{

//------------------------------------------------------------------------------
/**
 * 文字列
 *
 * このクラスは継承しないで下さい。
 */
class String{
public:
	//--------------------------------------------------------------------------
	// 文字列の構築、破棄
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 */
	String();

	/**
	 * コンストラクタ
	 *
	 * 文字列による初期化
	 * @param initString 初期化文字列
	 */
	String(const char* initString);

	/**
	 * コピーコンストラクタ
	 * @param copy コピー元
	 */
	String(const String& copy);

	/**
	 * 代入演算子
	 * @param copy 代入元
	 */
	String& operator =(const String& copy);

	/**
	 * 代入演算子
	 * @param copy 代入元
	 */
	String& operator =(const char* copy);

	/**
	 * デストラクタ
	 */
	~String();

	//--------------------------------------------------------------------------
	// 文字列の情報を取得する
	//--------------------------------------------------------------------------
	/**
	 * 文字列のバイト長を返す
	 *
	 * NULL終端を含まない文字列のバイト長を返します。
	 * @return 文字列のバイト長
	 */
	// 文字数と混同しないようにする為にlengthでは無くsizeにした。
	int getSize() const{ return size_; }

	/**
	 * 文字数を返す
	 * @return 文字列に含まれる文字の数
	 */
	// 使用頻度が低く、誤用を防ぐためにlengthでは無くCharacterCountにした。
	int getCharacterCount() const;

	/**
	 * 空文字列かどうか
	 * @return 空文字列ならtrueを返す。
	 */
	bool isEmpty() const{ return (size_ == 0); }

	/**
	 * バイトシーケンスの取得
	 *
	 * 取得したバイトシーケンスは文字列に変更が加えられた時に
	 * 失われる可能性があります。
	 * 取得したポインタのデータを直接書き換えるとStringが正しく動作しません。
	 * @return バイトシーケンス
	 */
	const char* getBytes() const{
		if(string_ != NULL){ return string_; }
		return &nullString;
	}

	/**
	 * 文字の取得
	 * @param index 取得する文字のインデックス
	 * @return インデックス位置にある文字
	 */
	char charAt(int index) const{
		Assert(index >= 0);
		Assert(index <= size_);
		if(string_ != NULL){ return string_[index]; }
		return nullString;
	}

	/**
	 * 部分文字列の取得
	 * @param beginIndex 部分文字列の開始位置
	 */
	String getSubstring(int beginIndex) const;

	/**
	 * 部分文字列の取得
	 * @param beginIndex 部分文字列の開始位置
	 * @param endIndex 部分文字列の終了位置(終了文字のインデックス + 1)
	 */
	String getSubstring(int beginIndex, int endIndex) const;

	/**
	 * 大文字化した文字列の取得
	 * @return 大文字化した文字列
	 */
	String getUpperCase() const;

	/**
	 * 小文字化した文字列の取得
	 * @return 小文字化した文字列
	 */
	String getLowerCase() const;

	/**
	 * ハッシュコードの取得
	 * @return ハッシュコード
	 */
	u_int getHashCode() const;

	//--------------------------------------------------------------------------
	// 文字列をパースする
	//--------------------------------------------------------------------------
	/**
	 * charへのパース
	 * @param value [out] char化された値が代入されます
	 * @return trueならパース成功
	 */
	bool parseChar(char* value) const;

	/**
	 * u_charへのパース
	 * @param value [out] u_char化された値が代入されます
	 * @return trueならパース成功
	 */
	bool parseUChar(u_char* value) const;

	/**
	 * shortへのパース
	 * @param value [out] short化された値が代入されます
	 * @return trueならパース成功
	 */
	bool parseShort(short* value) const;

	/**
	 * u_shortへのパース
	 * @param value [out] u_short化された値が代入されます
	 * @return trueならパース成功
	 */
	bool parseUShort(u_short* value) const;

	/**
	 * intへのパース
	 * @param value [out] int化された値が代入されます
	 * @return trueならパース成功
	 */
	bool parseInt(int* value) const;

	/**
	 * u_intへのパース
	 * @param value [out] u_int化された値が代入されます
	 * @return trueならパース成功
	 */
	bool parseUInt(u_int* value) const;

	/**
	 * floatへのパース
	 * @param value [out] float化された値が代入されます
	 * @return trueならパース成功
	 */
	bool parseFloat(float* value) const;

	/**
	 * doubleへのパース
	 * @param value [out] double化された値が代入されます
	 * @return trueならパース成功
	 */
	bool parseDouble(double* value) const;

	//--------------------------------------------------------------------------
	// 文字列を変更する
	//--------------------------------------------------------------------------
	/**
	 * 文字列の追加
	 * @param appendString 連結する文字列
	 * @return 変更済み文字列
	 */
	String& append(const String& appendString);

	/**
	 * 文字列の追加
	 * @param appendString 連結する文字列
	 * @return 変更済み文字列
	 */
	String& append(const char* appendString);

	/**
	 * 追加演算子
	 * @param appendString 追加文字列
	 * @return 変更済み文字列
	 */
	String& operator +=(const String& appendString){
		return append(appendString);
	}

	/**
	 * 追加演算子
	 * @param appendString 追加文字列
	 * @return 変更済み文字列
	 */
	String& operator +=(const char* appendString){
		return append(appendString);
	}

	/**
	 * フォーマット
	 *
	 * printfと同じ書式でフォーマットした文字列を設定する。
	 * %sでStringを入れる場合はgetBytes()が必要
	 * @param formatString フォーマット書式
	 * @param ... 可変長引数
	 * @return 変更済み文字列
	 */
	String& format(const char* formatString, ...);

	//--------------------------------------------------------------------------
	// 文字列を比較する
	//--------------------------------------------------------------------------
	/**
	 * 文字列の辞書式比較
	 * @param compareString 比較する文字列
	 */
	int compareTo(const String& compareString) const;

	/**
	 * 文字列の辞書式比較
	 * @param compareString 比較する文字列
	 */
	int compareTo(const char* compareString) const;

	/**
	 * 大文字、小文字を無視した文字列の辞書式比較
	 * @param compareString 比較する文字列
	 */
	int compareToIgnoreCase(const String& compareString) const;

	/**
	 * 文字列の比較
	 * @param compareString 比較する文字列
	 * @return 文字列が同じであればtrue
	 */
	bool equals(const String& compareString) const;

	/**
	 * 文字列の比較
	 * @param compareString 比較する文字列
	 * @return 文字列が同じであればtrue
	 */
	bool equals(const char* compareString) const;

	/**
	 * 文字列の比較
	 * @param compareString 比較する文字列
	 * @return 同じ値であればtrueを返す
	 */
	inline bool operator ==(const String& compareString) const{
		return equals(compareString);
	}

	/**
	 * 文字列の比較
	 * @param compareString 比較する文字列
	 * @return 同じ値でなければtrueを返す
	 */
	inline bool operator !=(const String& compareString) const{
		return !equals(compareString);
	}

	/**
	 * 大文字、小文字を無視した文字列の比較
	 * @param compareString 比較する文字列
	 * @return 文字列が同じであればtrue
	 */
	bool equalsIsIgnoreCase(const String& compareString) const;

	/**
	 * 指定した文字列で始まるかどうか
	 * @param prefix 比較する文字列
	 * @return 指定した文字列で始まっていればtrue
	 */
	bool startsWith(const String& prefix) const;

	/**
	 * 指定した文字列で始まるかどうか
	 * @param prefix 比較する文字列
	 * @return 指定した文字列で始まっていればtrue
	 */
	bool startsWith(const char* prefix) const;

	/**
	 * 指定した文字列で終わるかどうか
	 * @param suffix 比較する文字列
	 * @return 指定した文字列で終わっていればtrue
	 */
	bool endsWith(const String& suffix) const;

	/**
	 * 指定した文字列で終わるかどうか
	 * @param suffix 比較する文字列
	 * @return 指定した文字列で終わっていればtrue
	 */
	bool endsWith(const char* suffix) const;

	/**
	 * 指定された文字が最初に出現する位置のインデックスを取得
	 * @param searchChar 検索文字
	 * @return 最初に出現した位置のインデックス。無ければ-1を返す。
	 */
	int getIndexOf(const char searchChar) const;

	/**
	 * 指定された文字列が最初に出現する位置のインデックスを取得
	 * @param searchString 検索文字列
	 * @return 最初に出現した位置のインデックス。無ければ-1を返す。
	 */
	int getIndexOf(const char* searchString) const;

	/**
	 * 指定された文字列が最初に出現する位置のインデックスを取得
	 * @param searchString 検索文字列
	 * @return 最初に出現した位置のインデックス。無ければ-1を返す。
	 */
	int getIndexOf(const String& searchString) const;

	/**
	 * 指定された文字が最後に出現する位置のインデックスを取得
	 * @param searchChar 検索文字
	 * @return 最後に出現した位置のインデックス。無ければ-1を返す。
	 */
	int getLastIndexOf(const char searchChar) const;

	/**
	 * 指定された文字列が最後に出現する位置のインデックスを取得
	 * @param searchString 検索文字列
	 * @return 最後に出現した位置のインデックス。無ければ-1を返す。
	 */
	int getLastIndexOf(const char* searchString) const;

	/**
	 * 指定された文字列が最後に出現する位置のインデックスを取得
	 * @param searchString 検索文字列
	 * @return 最後に出現した位置のインデックス。無ければ-1を返す。
	 */
	int getLastIndexOf(const String& searchString) const;

#ifdef _DEBUG
	/**
	 * デバッグ用文字列情報出力
	 */
	void debugPrint();

#endif// End of _DEBUG

private:
	/**
	 * 内部使用コンストラクタ
	 *
	 * 文字列と長さによる初期化。空文字列を渡してはいけない。
	 * リファレンスカウンタをインクリメントしておく必要がある。
	 * @param initString 初期化文字列
	 * @param initLength 初期化文字列長
	 */
	String(char* initString, int initLength);

	// 文字列
	char* string_;
	// 文字列サイズ
	int size_;
	// ヌル文字列
	static const char nullString = '\0';
	// フォーマットデフォルト長
	static const int formatDefaultLength = 64;
	// フォーマットスケール
	static const int formatScale = 2;

};

//------------------------------------------------------------------------------
} // End of namespace Lamp
//------------------------------------------------------------------------------
/**
 * 文字列の連結
 * @param leftString 演算子の左側の文字列
 * @param rightString 演算子の右側の文字列
 * @return 連結された文字列
 */
const Lamp::String operator+(
	const Lamp::String& leftString, const Lamp::String& rightString);

//------------------------------------------------------------------------------
#endif // End of STRING_H_
//------------------------------------------------------------------------------
