#ifndef TTW_H_17E31558_F44F_46A3_BE2D_42CB88763682
#define TTW_H_17E31558_F44F_46A3_BE2D_42CB88763682

/// Tcl Thin Wrapper
/// License: Boost ver.1


#include "tcl.h"
#include "tk.h"
//#include "tommath.h"

class TTW_ListObj;

#ifdef TTW_EXPORTS
#define TTW_DECL __declspec(dllexport)
#else
#define TTW_DECL
#endif

/// ===================================
/// Tcl_DString を扱いやすくするクラス
class TTW_DECL TTW_DString{
	/// Tcl_DString のエンコーディングは状況依存
	/// どんなエンコーディングで入れても良い代わりに、
	/// どのエンコーディングで入っているかは使用者が管理する。
	Tcl_DString dstr;
public:
	/// ====== インスタンス生成 ======
	TTW_DString();
	TTW_DString(int length);
	TTW_DString(const char *str);
	TTW_DString(const char *str, int length);
	TTW_DString(const Tcl_DString &rhs); 
	TTW_DString(const TTW_DString &rhs); 
	TTW_DString(Tcl_Obj *obj); // Tcl_Obj の内部形式は utf-8 

	TTW_DString &operator =(const char *rhs);
	TTW_DString &operator =(const Tcl_DString &rhs);
	TTW_DString &operator =(const TTW_DString &rhs);
	TTW_DString &operator =(Tcl_Obj *obj);
	~TTW_DString();

	/// ====== 文字のセット、追加 ======
	// 引数の Tcl_DString を自インスタンスに移動する。
	TTW_DString &Move(Tcl_DString &rhs);
	TTW_DString &Move(TTW_DString &rhs);

	TTW_DString &Set(const char *str, int length);
	TTW_DString &Append(const char *str, int length);

	TTW_DString &operator << (const char *rhs);
	TTW_DString &operator << (const Tcl_DString &rhs);
	TTW_DString &operator << (const TTW_DString &rhs);
	TTW_DString &operator << (Tcl_Obj *obj);

	/// ====== 文字コード変換 ======
	// 引数で与えられたシステムエンコーディング文字列を UTF8 に変換して格納する
	TTW_DString &SysToUtf8(const char *str, bool append = true);
	TTW_DString &SysToUtf8(const char *str, int length, bool append = true);
	TTW_DString &SysToUtf8(const Tcl_DString &str, bool append = true);
	TTW_DString &SysToUtf8(const TTW_DString &str, bool append = true);

	// 引数で与えられた 文字列を指定されたエンコーディングとみなし、UTF8 に変換して格納する
	TTW_DString &ToUtf8(Tcl_Encoding src_enc, const char *str, bool append = true);
	TTW_DString &ToUtf8(Tcl_Encoding src_enc, const char *str, int length, bool append = true);
	TTW_DString &ToUtf8(Tcl_Encoding src_enc, const Tcl_DString &str, bool append = true);
	TTW_DString &ToUtf8(Tcl_Encoding src_enc, const TTW_DString &str, bool append = true);

	// 引数で与えられた UTF8 文字列をシステムエンコーディングに変換して格納する
	TTW_DString &Utf8ToSys(const char *str, bool append = true);
	TTW_DString &Utf8ToSys(const char *str, int length, bool append = true);
	TTW_DString &Utf8ToSys(const Tcl_DString &str, bool append = true);
	TTW_DString &Utf8ToSys(const TTW_DString &str, bool append = true);
	TTW_DString &Utf8ToSys(Tcl_Obj *obj, bool append = true);

	// 引数で与えられた UTF8 文字列を指定されたエンコーディングに変換して格納する
	TTW_DString &Utf8To(Tcl_Encoding dst_enc, const char *utf8_str, bool append = true);
	TTW_DString &Utf8To(Tcl_Encoding dst_enc, const char *utf8_str, int length, bool append = true);
	TTW_DString &Utf8To(Tcl_Encoding dst_enc, const Tcl_DString &utf8_str, bool append = true);
	TTW_DString &Utf8To(Tcl_Encoding dst_enc, const TTW_DString &utf8_str, bool append = true);
	TTW_DString &Utf8To(Tcl_Encoding dst_enc, Tcl_Obj *obj, bool append = true);

	/// ====== 生文字列取得 ======
	operator const char *() const;
	operator char *();
	const char *Value() const;
	char *Value();
	operator Tcl_DString &();

	/// ====== 文字列長取得、変更 ======
	int Length() const;
	void SetLength(int len);
	void Clear();

	/// ====== Tcl List関連 ======
	// 末尾に { をつける。 最後の文字がスペース系でない場合はスペースも入れる。
	void StartSubList();
	// 末尾に } をつける。
	void EndSubList();

	TTW_DString &AppendElement(const char *rhs);
	TTW_DString &AppendElement(const Tcl_DString &rhs);
	TTW_DString &AppendElement(const TTW_DString &rhs);
	TTW_DString &AppendElement(Tcl_Obj *obj);

};

/// UTF-8 文字列処理用のTcl C API群 
// 文字列比較
// Tcl_UtfNcmp         : 大文字・小文字の区別をする比較
// Tcl_UtfNcasecmp     : 大文字・小文字を同じ扱いとする比較
// Tcl_StringCaseMatch : パターン(*?\[])を使った比較。3つ目の引数は大文字・小文字の区別の有無の指定(0:区別する、TCL_MATCH_NOCASE:同じ扱い)

// 検索
// Tcl_UtfFindFirst    : 指定した Unicode 文字を検索し、最初に一致した文字のポインタを返す。
// Tcl_UtfFindLast     : 指定した Unicode 文字を検索し、最後に一致した文字のポインタを返す。

// 大文字・小文字変換
// Tcl_UtfToUpper      : 小文字を大文字に変換する。
// Tcl_UtfToLower      : 大文字を小文字に変換する。
// Tcl_UtfToTitle      : 最初の1文字を大文字に、2文字目以降を小文字に変換する。

// ポインタ移動
// Tcl_UtfNext         : 次の文字のポインタを返す。
// Tcl_UtfPrev         : 一つ前の文字のポインタを返す。安全に処理する為、先頭位置を示すポインタを2番目の引数に指定する。戻れない位置を指定した場合は先頭位置のポインタを返す。
// Tcl_UtfAtIndex      : N 番目(Nバイト目ではない)の文字のポインタを返す。

// 他
// Tcl_NumUtfChars     : 文字数(バイト数ではない)を取得する。
// Tcl_UtfCharComplete : UTF-8 文字として完結しているか確認する。

// TTW_UtfToUniChar    : UTF-8 文字一文字を取得する。Unicode文字を chPtr に、UTF-8 文字長を戻り値に返す。
#define TTW_UtfToUniChar(src, chPtr) \
	((static_cast<unsigned int>(*(src)) < 0x80) ? (((*(chPtr)) = static_cast<Tcl_UniChar>(*(src))), 1) : \
	::Tcl_UtfToUniChar(src, chPtr))

// XPG3 対応の printf
TTW_DECL TTW_DString &TTW_Format(Tcl_Interp *interp, TTW_DString &utf8_lhs, const char *utf8_fmt, const TTW_ListObj &rhs);
TTW_DECL TTW_DString &TTW_Format(TTW_DString &utf8_lhs, const char *utf8_fmt, const TTW_ListObj &rhs);

/// UTF-8 文字列を任意のデリミタで Split するクラス
class TTW_DECL TTW_SplitUTF8String{
	const char *utf8str, *utf8delimiter, *iter, *utf8str_e;
	int delimiter_len;
	TTW_SplitUTF8String();
	TTW_SplitUTF8String(const TTW_SplitUTF8String &);
	TTW_SplitUTF8String &operator =(const TTW_SplitUTF8String &);
public:
	TTW_SplitUTF8String(const char *utf8str, const char *utf8delimiter);
	bool Next(const char *&utf8tok_start, int &tok_len);
	~TTW_SplitUTF8String();
};

/// ===================================
/// Tcl_ListObj を扱いやすくするクラス
/// 処理効率を上げるため、次のような挙動をする。
/// 引数なしコンストラクタで生成された場合  : listObj は NULL 
/// listObj が NULL の状態での各処理の挙動
/// ・リスト内要素を取得しようとした場合         : listObj は NULL のまま、 NULL を返す。
/// ・リスト自体のポインタを取得しようとした場合 : listObj を生成し、そのポインタを返す。
/// ・リスト要素に項目を追加しようとした場合     : listObj を生成し、要素を追加する。
/// ・リスト要素から項目を削除しようとした場合   : listObj は NULL のままで何もしない。
/// borrow 状態のオブジェクトは、 TTW_ListObj で生存期間の管理をしない(TTW_ListObj は参照カウンタを増減させない)。
/// それ以外のオブジェクトは、TTW_ListObj の生存期間とリンクするように参照カウンタを増減する。 
class TTW_DECL TTW_ListObj{
	Tcl_Obj *listObj;
	bool borrowed;
	Tcl_Interp *interp; // エラー情報取得用
public:
	/// ====== インスタンス生成 ======
	TTW_ListObj();
	TTW_ListObj(int objc, Tcl_Obj *objv[]);
	TTW_ListObj(const TTW_ListObj &rhs);
	TTW_ListObj & operator = (const TTW_ListObj &rhs);

	/// オブジェクトの生存期間管理を元のコンテナに託したまま、各種操作をしたい時に呼び出す。
	///    Tcl の参照カウンタは、2 以上(共有状態)のままでは各種編集ができないようになっている。
	///    どうやら専らコピーオンライト(共有状態で編集処理が呼び出されたときにコピー実施)の目的で実装されているらしい。
	///    Tcl_Interp 等が管理しているオブジェクトを TTW_ListObj を使って操作・編集するために、
	///    オブジェクトを借りる(参照カウンタを上げずにポインタだけ持つ)ことができるようにした。
	TTW_ListObj & Borrow(Tcl_Obj *listObj);
	TTW_ListObj & Copy(Tcl_Obj *listObj);
	~TTW_ListObj();

	/// ====== interp設定 ======
	void SetInterp(Tcl_Interp *interp);
	Tcl_Interp *GetInterp();

	/// ====== 生リストObj取得 ======
	// 生リスト Obj の参照カウンタはうかつに変えないこと
	// 不用意に Tcl_IncrRefCount すると、Borrow のところで記載した理由により、要素追加時等に Tcl_Panic が発生する。
	// また不用意に Tcl_DecrRefCount するとその瞬間にオブジェクトが破棄され、 後で TTW_ListObj が(Borrow した場合は Borrow 元のコンテナが)
	// 破棄された時に破棄済のオブジェクトを操作してしまうため、実行時エラーが発生する。
	operator Tcl_Obj *();
//	operator Tcl_Obj *() const;
	Tcl_Obj *operator [](int idx);
	const Tcl_Obj *operator [](int idx) const;
	int Count() const;

	/// ====== スタック風の処理 ======
	Tcl_Obj *Push(Tcl_Obj *); // スタックの他に、RAII リソース管理用コンテナ(TTW_ListObj 解放のタイミングで Push した Tcl_Obj 群も解放させる)としても使える。
	Tcl_Obj *Push(bool b);
	Tcl_Obj *Push(int i);
	Tcl_Obj *Push(long l);
	Tcl_Obj *Push(double d);
	Tcl_Obj *Push(Tcl_WideInt &wi);
	Tcl_Obj *Push(mp_int &mp);

	// 引数に渡す文字列は、UTF-8 でエンコーディングされていること
	Tcl_Obj *Push(const char *utf8);
	Tcl_Obj *Push(Tcl_DString &utf8);
	Tcl_Obj *Push(const TTW_DString &utf8);

	Tcl_Obj *Last();
	void Pop(); // 戻り値として Tcl_Obj * とできないのは、 返されたときにはすでに参照カウントが引かれて解放された後の可能性があるため。

	/// ====== 要素追加 ======
	TTW_ListObj &operator << (bool b);
	TTW_ListObj &operator << (int i);
	TTW_ListObj &operator << (long l);
	TTW_ListObj &operator << (double d);
	TTW_ListObj &operator << (Tcl_WideInt &wi);
	TTW_ListObj &operator << (mp_int &mp);

	// 引数に渡す文字列は、UTF-8 でエンコーディングされていること
	TTW_ListObj &operator << (const char *utf8);
	TTW_ListObj &operator << (Tcl_DString &utf8);
	TTW_ListObj &operator << (const TTW_DString &utf8);

	TTW_ListObj &operator << (Tcl_Obj *obj);     // 他のコンテナに所有されている場合、Sharedになる点に注意
	TTW_ListObj &operator << (TTW_ListObj &obj); // 他のコンテナに所有されている場合、Sharedになる点に注意
	
	/// ====== 要素変更 ======
	Tcl_Obj *Set (int idx, bool b);
	Tcl_Obj *Set (int idx, int i);
	Tcl_Obj *Set (int idx, long l);
	Tcl_Obj *Set (int idx, double d);
	Tcl_Obj *Set (int idx, const Tcl_WideInt &wi);
	Tcl_Obj *Set (int idx, mp_int &mp);

	// 引数に渡す文字列は、UTF-8 でエンコーディングされていること
	Tcl_Obj *Set (int idx, const char *utf8);
	Tcl_Obj *Set (int idx, Tcl_DString &utf8);
	Tcl_Obj *Set (int idx, const TTW_DString &utf8);

	Tcl_Obj *Set (int idx, Tcl_Obj *obj);     // 他のコンテナに所有されている場合、Sharedになる点に注意
	Tcl_Obj *Set (int idx, TTW_ListObj &obj); // 他のコンテナに所有されている場合、Sharedになる点に注意

	/// ====== 要素全削除 ======
	void Clear();

	/// ====== Tcl コマンド実行 ======
	Tcl_Obj *Eval(Tcl_Interp *interp, int flags = 0); /// 自インスタンスのリストでEvalを実行。戻り値はResultオブジェクト
};

/// Tcl_List 処理用のTcl C API群
// Tcl_ListObjGetElements : リストの内容を表す Tcl_Obj 配列の先頭ポインタと要素数を取得する。
// Tcl_ListObjReplace     : リストの特定の範囲を、指定した Tcl_Obj 配列の内容に差し替える。
// Tcl_ListObjAppendList  : リストの末尾に別のリストの内容を追加する。
// Tcl_SetListObj         : これまでのリストの内容を消して、指定したTcl_Obj配列をリストにセットする。

/// ===================================
/// Tcl_DictObj を扱いやすくするクラス
/// 処理効率を上げるため、次のような挙動をする。
/// 引数なしコンストラクタで生成された場合  : dictObj は NULL 
/// dictObj が NULL の状態での各処理の挙動
/// ・Dict内要素を取得しようとした場合         : dictObj は NULL のまま、 NULL を返す。
/// ・Dict自体のポインタを取得しようとした場合 : dictObj を生成し、そのポインタを返す。
/// ・Dict要素に項目を追加しようとした場合     : dictObj を生成し、要素を追加する。
/// ・Dict要素から項目を削除しようとした場合   : dictObj は NULL のままで何もしない。
/// borrow 状態のオブジェクトは、 TTW_DictObj で生存期間の管理をしない(TTW_DictObj は参照カウンタを増減させない)。
/// それ以外のオブジェクトは、TTW_DictObj の生存期間とリンクするように参照カウンタを増減する。 
class TTW_DECL TTW_DictObj{
	Tcl_Obj *dictObj;
	bool borrowed;
	Tcl_Interp *interp; // エラー情報取得用
public:
	/// ====== インスタンス生成 ======
	TTW_DictObj();
	TTW_DictObj(const TTW_DictObj &rhs);
	TTW_DictObj & operator = (const TTW_DictObj &rhs);

	/// オブジェクトの生存期間管理を元のコンテナに託したまま、各種操作をしたい時に呼び出す。
	///    Tcl の参照カウンタは、2 以上(共有状態)のままでは各種編集ができないようになっている。
	///    どうやら専らコピーオンライト(共有状態で編集処理が呼び出されたときにコピー実施)の目的で実装されているらしい。
	///    Tcl_Interp 等が管理しているオブジェクトを TTW_ListObj を使って操作・編集するために、
	///    オブジェクトを借りる(参照カウンタを上げずにポインタだけ持つ)ことができるようにした。
	TTW_DictObj & Borrow(Tcl_Obj *listObj);
	TTW_DictObj & Copy(Tcl_Obj *listObj);
	~TTW_DictObj();

	/// ====== interp設定 ======
	void SetInterp(Tcl_Interp *interp);
	Tcl_Interp *GetInterp();

	/// ====== 生リストObj取得 ======
	// 生リスト Obj の参照カウンタはうかつに変えないこと
	// 不用意に Tcl_IncrRefCount すると、Borrow のところで記載した理由により、要素追加時等に Tcl_Panic が発生する。
	// また不用意に Tcl_DecrRefCount するとその瞬間にオブジェクトが破棄され、 後で TTW_ListObj が(Borrow した場合は Borrow 元のコンテナが)
	// 破棄された時に破棄済のオブジェクトを操作してしまうため、実行時エラーが発生する。
	operator Tcl_Obj *();

	int Count() const;

	/// ====== キーから値を取得。見つからない場合は NULLを返す ======
	Tcl_Obj *operator [](const char *key);
	Tcl_Obj *operator [](Tcl_Obj *key);
	const Tcl_Obj *operator [](const char *key) const;
	const Tcl_Obj *operator [](const Tcl_Obj *key) const;

	/// ====== 要素の列挙 ======
	class Iter{
		Tcl_Obj *dictObj, *keyObj, *valObj;
		Tcl_DictSearch searchPtr;
		int done;
		Iter(const Iter &);
		Iter & operator =(const Iter &);
	public:
		Iter(TTW_DictObj &dictObj);
		~Iter();
		bool Done() const;
		bool Next();

		Tcl_Obj *Key();
		Tcl_Obj *Value();
	};

	/// ====== 要素の追加/書き換え ======
	Tcl_Obj *Put(const char *key, Tcl_Obj *val); 
	Tcl_Obj *Put(const char *key, bool b);
	Tcl_Obj *Put(const char *key, int i);
	Tcl_Obj *Put(const char *key, long l);
	Tcl_Obj *Put(const char *key, double d);
	Tcl_Obj *Put(const char *key, Tcl_WideInt &wi);
	Tcl_Obj *Put(const char *key, mp_int &mp);
	Tcl_Obj *Put(Tcl_Obj *key, Tcl_Obj *val); 
	Tcl_Obj *Put(Tcl_Obj *key, bool b);
	Tcl_Obj *Put(Tcl_Obj *key, int i);
	Tcl_Obj *Put(Tcl_Obj *key, long l);
	Tcl_Obj *Put(Tcl_Obj *key, double d);
	Tcl_Obj *Put(Tcl_Obj *key, Tcl_WideInt &wi);
	Tcl_Obj *Put(Tcl_Obj *key, mp_int &mp);

	// 引数に渡す文字列は、UTF-8 でエンコーディングされていること
	Tcl_Obj *Put(const char *key, const char *utf8);
	Tcl_Obj *Put(const char *key, Tcl_DString &utf8);
	Tcl_Obj *Put(const char *key, const TTW_DString &utf8);
	Tcl_Obj *Put(Tcl_Obj *key, const char *utf8);
	Tcl_Obj *Put(Tcl_Obj *key, Tcl_DString &utf8);
	Tcl_Obj *Put(Tcl_Obj *key, const TTW_DString &utf8);

	/// ====== 要素全削除 ======
	void Clear();
};

/// ===================================
/// Tcl_Obj から値を取得する関数群
TTW_DECL bool TTW_GetBoolean(Tcl_Interp *interp, Tcl_Obj *obj, bool when_null = false);
TTW_DECL bool TTW_GetBoolean(Tcl_Obj *obj, bool when_null = false);

// ByteArray

TTW_DECL double TTW_GetDouble(Tcl_Interp *interp, Tcl_Obj *obj, double when_null = 0);
TTW_DECL double TTW_GetDouble(Tcl_Obj *obj, double when_null = 0);

// Index

TTW_DECL int TTW_GetInt(Tcl_Interp *interp, Tcl_Obj *obj, int when_null = 0);
TTW_DECL int TTW_GetInt(Tcl_Obj *obj, int when_null = 0);

TTW_DECL long TTW_GetLong(Tcl_Interp *interp, Tcl_Obj *obj, long when_null = 0);
TTW_DECL long TTW_GetLong(Tcl_Obj *obj, long when_null = 0);

TTW_DECL const char *TTW_GetString(Tcl_Obj *obj, const char *when_null = 0);
TTW_DECL const char *TTW_GetString(Tcl_Obj *obj, int &length, const char *when_null = 0);

TTW_DECL Tcl_UniChar *TTW_GetUnicode(Tcl_Obj *obj, Tcl_UniChar *when_null = 0);
TTW_DECL Tcl_UniChar *TTW_GetUnicode(Tcl_Obj *obj, int &length, Tcl_UniChar *when_null = 0);

TTW_DECL Tcl_WideInt TTW_GetWideInt(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_WideInt when_null = 0);
TTW_DECL Tcl_WideInt TTW_GetWideInt(Tcl_Obj *obj, Tcl_WideInt when_null = 0);

//mp_int TTW_GetBignum(Tcl_Interp *interp, Tcl_Obj *obj);
//mp_int TTW_GetBignum(Tcl_Obj *obj);

// RegExp

/// ===================================
/// ファイル操作関連
// ファイルの状態
// Tcl_FSAccess          : ファイルの存在確認、および読み・書き・実行(R_OK、W_OK、X_OK)モード確認
// Tcl_FSStat            : 指定したパスが示すファイル/ディレクトリの詳細情報の取得(作成・更新日時、ファイルサイズ、参照数、ファイルかディレクトリか、等)
//                         Tcl_StatBuf は stat の typedef のため、使用する際は #include <sys/stat.h> すること

// ファイル操作
// Tcl_FSCopyFile        : ファイルをコピーする。
// Tcl_FSRenameFile      : ファイル名を変更する。
// Tcl_FSDeleteFile      : ファイルを削除する。
// Tcl_FSLink            : ファイル/ディレクトリのシンボリック/ハードリンクを作成する。Windows版Tcl(8.5.15)の場合の対応状況は下記の通り
//                                       シンボリック   ハード
//                        ファイル            ×          〇       (Win Vista以降 ファイルのシンボリックリンクが作れるようになったが、上記バージョンの Tcl は未対応)
//                        ディレクトリ        〇          ×

// ファイル内容読み書き(チャンネル操作)
// Tcl_FSOpenFileChannel : ファイルチャンネルを開く
// Tcl_Seek              : チャンネルの読み書きのポジションを移動する。
// Tcl_Tell              : チャンネルの読み書きのポジションを取得する。
// Tcl_Flush             : チャンネルをフラッシュする。
// Tcl_Eof               : チャンネルの終端に達したかどうかを判定する。
// Tcl_Close             : チャンネルを閉じる。
// Tcl_SetChannelOption  : チャンネルのオプション(ブロッキング有無、バッファリング有無、バッファサイズ、改行モード、エンコーディング)を設定する
// Tcl_GetsObj           : チャンネルから 1 行分の文字列を UTF-8 に変換しながら取得し、指定した Tcl_Obj に追記する。
// Tcl_WriteChars        : UTF-8 文字列を、指定されたエンコーディングに変換しながらチャンネルに書き込む。
//                         改行は "\n" で指定する。改行コードは指定された改行モードに応じて適宜変換される。
// Tcl_Read, Tcl_ReadRaw : チャンネルから指定したバイト数のデータを読み込む。エンコーディングの変換は実施しない。
// Tcl_Write,Tcl_WriteRaw: チャンネルに指定したバイト数のデータを書き込む。エンコーディングの変換は実施しない。

// ディレクトリ操作
// Tcl_FSCreateDirectory : ディレクトリを作成する。
// Tcl_FSCopyDirectory   : ディレクトリをコピーする。
// Tcl_FSRemoveDirectory : ディレクトリを削除する。空の場合だけ削除するか、空でなくても全て削除するかをフラグで選択できる。
// Tcl_FSGetCwd          : カレントディレクトリを取得する。interp はエラー情報取得のためだけに使用しているため、エラー情報が不要な場合は NULL でも問題ない。
// Tcl_FSChdir           : カレントディレクトリを変更する。

// パス編集
// Tcl_FSJoinPath          : リストで与えられた各要素を結合してパスにする。
// Tcl_FSSplitPath         : パスを分解してリストに格納する。
// Tcl_FSEqualPaths        : 同じパスを指しているかどうかを判定する。 必要に応じて 内部で Tcl_FSGetNormalizedPath を使用する。
// Tcl_FSGetNormalizedPath : パス名を正規化する。相対パス vs. 絶対パスや、../ 等の有無、及び Windows の場合のshortname/longname、及び大文字小文字同一扱い等にも対応している。
// Tcl_FSJoinToPath        : パスにディレクトリ名やファイル名を示す要素を結合する。
Tcl_Obj *TTW_FSJoinToPath (Tcl_Obj *pathPtr, TTW_ListObj &list); // Tcl_FSJoinToPath の TTW_ListObj 版
// Tcl_FSGetNativePath     : ネイティブなパス文字列を取得する。
// Tcl_FSGetPathType       : パスが絶対パスか、ボリューム相対パスか、相対パスかを調べる。

/// ===================================
/// 時間処理関連
// Tcl_GetTime             : 1970年1月1日からの経過時間を取得する。
// Tcl_Sleep               : 指定したミリ秒、自スレッドを止める。
class TTW_DECL TTW_LapTimeWatch {
	struct Impl;
	Impl *pimpl;
	TTW_LapTimeWatch(const TTW_LapTimeWatch &);
	TTW_LapTimeWatch &operator =(const TTW_LapTimeWatch &);
public:
	enum Type{
		Sequence = 0, 
		// Lap を呼び出した順に、name と経過時間(ミリ秒)のペアを取得する。
		// 例:
		// tw.Lap("line:100", Sequence); // [1]
		// ...
		// tw.Lap("line:110", Sequence); // [2]
		// ...
		// tw.Lap("line:130", Sequence); // [3]
		// TTW_ListObj &r = tw.AnalyzeSequenceResult();
		// とした場合、
		//   { {line:100} 0 {line:110} xxx {line:130} yyy } }
		//   xxx : [1]->[2] の経過ミリ秒
		//   yyy : [2]->[3] の経過ミリ秒
		//  といったリストが生成される。リストの生存期間は TTW_LapTimeWatch と同じ。
		LoopPoint = 1,
		// ループ内の指定した位置で計測した回数(通過回数 - 1)と、平均通過間隔を取得する。
		// 例:
		// for (int j = 0; j < 100; ++j){
		//   tw.Lap("loop 1", LoopPoint);
		//   ...
		// }
		// for (int j = 0; j < 150; ++j){
		//   tw.Lap("loop 2", LoopPoint);
		//   ...
		// }
		// TTW_ListObj &r = tw.AnalyzeLoopPoint();
		// とした場合、
		//   { {loop 1} 99 xxx {loop 2} 149 yyy } (名前、計測回数(= 通過回数 - 1)、平均通過間隔の順)
		//  といったリストが生成される。リストの生存期間は TTW_LapTimeWatch と同じ。
		LoopStart = 2, LoopEnd = 3
		// ループ内の指定した範囲を通った回数と、平均通過間隔を取得する。
		// 例:
		// for (int j = 0; j < 100; ++j){
		//   ...
		//   tw.Lap("range 1", LoopStart);
		//   ...
		//   tw.Lap("range 1", LoopEnd);
		//   ...
		// }
		// for (int j = 0; j < 150; ++j){
		//   ...
		//   tw.Lap("range 2", LoopStart);
		//   ...
		//   tw.Lap("range 2", LoopEnd);
		//   ...
		// }
		// TTW_ListObj &r = tw.AnalyzeLoopPoint();
		// とした場合、
		//   { {range 1} 100 xxx {range 2} 150 yyy } (名前、通過回数、平均通過間隔の順)
		//  といったリストが生成される。リストの生存期間は TTW_LapTimeWatch と同じ。
	};
	TTW_LapTimeWatch();
	~TTW_LapTimeWatch();
	void Reset();
	void Lap(const char *name = "", Type type = Sequence);

	// Sequence タイプの Lap 結果を文字列形式で出力する。
	TTW_ListObj &AnalyzeSequenceResult();
	TTW_ListObj &AnalyzeLoopPoint();
	// 処理ルール : 同じ名前の LoopStart、LoopEnd は、最初に呼び出されたものから順に処理して、一番近いもの同士でペアにする。
	//  対応しない LoopStart/LoopEnd は下記ルールで処理する。
	//  * LoopStart を呼び出す前に出現する LoopEnd は無視。
	//  * LoopStart の後に LoopEnd が出現しない LoopStart は無視。
	//  * 同じ名前で連続して LoopStart を呼び出した場合は、先に呼び出した方の LoopStart を無視。
	//  * 同じ名前で連続して LoopEnd を呼び出した場合は、後に呼び出した方の LoopEnd を無視。
	TTW_ListObj &AnalyzeLoopRange();
};

/// ===================================
/// Tcl_ObjType 取得
TTW_DECL const Tcl_ObjType *TTW_GetDictType();
TTW_DECL const Tcl_ObjType *TTW_GetListType();
TTW_DECL const Tcl_ObjType *TTW_GetIntType();
TTW_DECL const Tcl_ObjType *TTW_GetWideIntType();
TTW_DECL const Tcl_ObjType *TTW_GetDoubleType();
TTW_DECL const Tcl_ObjType *TTW_GetBooleanType();
TTW_DECL const Tcl_ObjType *TTW_GetStringType();

/// ===================================
/// json 処理 (jansson)

TTW_DECL Tcl_Obj *TTW_json_create_null();
TTW_DECL Tcl_Obj *TTW_json_create_true();
TTW_DECL Tcl_Obj *TTW_json_create_false();

// null型
TTW_DECL bool TTW_json_is_null(const Tcl_Obj *json);
TTW_DECL bool TTW_json_is_object(const Tcl_Obj *json);
TTW_DECL bool TTW_json_is_array(const Tcl_Obj *json);
TTW_DECL bool TTW_json_is_integer(const Tcl_Obj *json);
TTW_DECL bool TTW_json_is_real(const Tcl_Obj *json);
TTW_DECL bool TTW_json_is_number(const Tcl_Obj *json);
TTW_DECL bool TTW_json_is_boolean(const Tcl_Obj *json);
TTW_DECL int TTW_json_array_count(const Tcl_Obj *json); // 指定した要素が配列型でない場合は -1 を返す。

#define TTW_JSON_REJECT_DUPLICATES  0x1
#define TTW_JSON_DISABLE_EOF_CHECK  0x2
#define TTW_JSON_DECODE_ANY         0x4
#define TTW_JSON_DECODE_INT_AS_REAL 0x8
#define TTW_JSON_ALLOW_NUL          0x10
TTW_DECL Tcl_Obj *TTW_json_load(const char *string, size_t flags, Tcl_Obj *error);
TTW_DECL Tcl_Obj *TTW_json_load(const char *buffer, size_t buflen, size_t flags, Tcl_Obj *error);
TTW_DECL Tcl_Obj *TTW_json_load_file(const char *path, size_t flags, Tcl_Obj *error);

#define TTW_JSON_COMPACT            0x20
#define TTW_JSON_ENSURE_ASCII       0x40
#define TTW_JSON_SORT_KEYS          0x80
#define TTW_JSON_PRESERVE_ORDER     0x100
#define TTW_JSON_ENCODE_ANY         0x200
#define TTW_JSON_ESCAPE_SLASH       0x400
#define TTW_JSON_REAL_PRECISION(n)  (((n) & 0x1F) << 11)
#define TTW_JSON_EMBED              0x10000
TTW_DECL bool TTW_json_dump(Tcl_Obj *json, size_t flags, TTW_DString &output);
TTW_DECL bool TTW_json_dump(Tcl_Obj *json, size_t flags, Tcl_DString *output);
TTW_DECL bool TTW_json_dump(Tcl_Obj *json, size_t flags, Tcl_Obj *output);
TTW_DECL bool TTW_json_dump_file(Tcl_Obj *json, size_t flags, const char *path);

#endif // TTW_H_17E31558_F44F_46A3_BE2D_42CB88763682
