//
//	clipenm.cs
//
//	列挙定義
//
//	CLiP - Common Library for P/ECE
//	Copyright (C) 2017 Naoyuki Sawa
//
//	* Mon Feb 27 22:08:56 JST 2017 Naoyuki Sawa
//	- 1st リリース。
//	* Fri Mar 03 22:34:24 JST 2017 Naoyuki Sawa
//	- clipptr_net.csモジュールを追加した事に伴い、ポインタの扱いを大幅に変更しました。
//	  これまでは、配列とインデクスを保持する必要が有りましたが、今後はC言語版と同様に、配列ポインタ一つを保持すれば良くなりました。
//	- 今回は変更量がかなり多かったので、変更前のコードはコメントアウトして残していません。
//	  変更前のコードを参照する場合は、前回のアーカイブを参照して下さい。
//
using System;
namespace org.piece_me {
	public static partial class libclip {
		//*****************************************************************************
		//	定数
		//*****************************************************************************
		public const int Enm_name	= 1;		//シンボルの名前
		public const int Enm_desc	= 2;		//シンボルの説明文
		//*****************************************************************************
		//	基本的な関数
		//*****************************************************************************
		//名前の文字列を返す。
		public static string EnmDef_GetName(VoidPtr pEnmKey, int iEnmDef, int iVal) {
			VoidPtr pEnmDef;
			string pName;
			//列挙型の値のキーを取得する。
			pEnmDef = REG_open_key_l(pEnmKey, iEnmDef, iVal);
			if(!pEnmDef) { throw new ApplicationException(); }	//列挙型の値のキーが無ければエラー。iEnmDef,又は,iValが間違っている。多分呼び出し側のバグ。
			//名前の文字列を取得する。
			pName = REG_get_string(pEnmDef, Enm_name);
			if(pName == null) { throw new ApplicationException(); }	//名前の文字列が無ければエラー。dEnmDefC.exeは名前の文字列を必ず格納しているはず。多分データ破損,又は,ツールバグ。
			//名前の文字列を返す。
			return pName;
		}
		//-----------------------------------------------------------------------------
		//説明文の文字列を返す。説明文の文字列が格納されていなければnullを返す。
		public static string EnmDef_GetDesc(VoidPtr pEnmKey, int iEnmDef, int iVal) {
			VoidPtr pEnmDef;
			string pDesc;
			//列挙型の値のキーを取得する。
			pEnmDef = REG_open_key_l(pEnmKey, iEnmDef, iVal);
			if(!pEnmDef) { throw new ApplicationException(); }	//列挙型の値のキーが無ければエラー。iEnmDef,又は,iValが間違っている。多分呼び出し側のバグ。
			//説明文の文字列を取得する。
			pDesc = REG_get_string(pEnmDef, Enm_desc);
		//不要	if(pDesc == null) { throw new ApplicationException(); }	//説明文の文字列は無い可能性も有る。列挙定義スクリプトにて説明文が指定されなかった場合はdEnmDefC.exeは説明文の文字列を格納しない。
			//説明文の文字列を返す。説明文の文字列が格納されていなければnullを返す。
			return pDesc;
		}
		//-----------------------------------------------------------------------------
		//説明文の文字列を返す。説明文の文字列が格納されていなければ名前の文字列を返す。
		public static string EnmDef_ToStr(VoidPtr pEnmKey, int iEnmDef, int iVal) {
			VoidPtr pEnmDef;
			string pStr;
			//列挙型の値のキーを取得する。
			pEnmDef = REG_open_key_l(pEnmKey, iEnmDef, iVal);
			if(!pEnmDef) { throw new ApplicationException(); }	//列挙型の値のキーが無ければエラー。iEnmDef,又は,iValが間違っている。多分呼び出し側のバグ。
			//説明文の文字列を取得する。
			pStr = REG_get_string(pEnmDef, Enm_desc);
			//説明文の文字列が格納されていなければ…
			if(pStr == null) {	//説明文の文字列は無い可能性も有る。列挙定義スクリプトにて説明文が指定されなかった場合はdEnmDefC.exeは説明文の文字列を格納しない。
				//名前の文字列を取得する。
				pStr = REG_get_string(pEnmDef, Enm_name);
				if(pStr == null) { throw new ApplicationException(); }	//名前の文字列が無ければエラー。dEnmDefC.exeは名前の文字列を必ず格納しているはず。多分データ破損,又は,ツールバグ。
			}
			//説明文の文字列を返す。説明文の文字列が格納されていなければ名前の文字列を返す。
			return pStr;
		}
		//*****************************************************************************
		//	ユーティリティ関数
		//*****************************************************************************
		//列挙型に属する値の数を返す。
		public static int EnmDef_GetNum(VoidPtr pEnmKey, int iEnmDef) {
			int n = REG_num_key_l(pEnmKey, iEnmDef);	//REG_num_value_l()ではない事に注意せよ。列挙型のレジストリ構造はpEnmKey⇒列挙型のキー⇒列挙型の値のキー⇒値の名前[,説明文]という構造である。
			if(n == 0) { throw new ApplicationException(); }	//列挙型の値のキーが無ければエラー。iEnmDefが間違っている。多分呼び出し側のバグ。
			return n;
		}
		//-----------------------------------------------------------------------------
		//列挙型に属する値のうち、最小値を返す。
		public static int EnmDef_GetMin(VoidPtr pEnmKey, int iEnmDef) {
			return EnmDef_GetNth(pEnmKey, iEnmDef, 0);
		}
		//-----------------------------------------------------------------------------
		//列挙型に属する値のうち、最大値を返す。
		public static int EnmDef_GetMax(VoidPtr pEnmKey, int iEnmDef) {
			return EnmDef_GetNth(pEnmKey, iEnmDef,
			       EnmDef_GetNum(pEnmKey, iEnmDef) - 1);
		}
		//-----------------------------------------------------------------------------
		//列挙型に属する値のうち、index番目の値を返す。index番目の値が無ければ、エラー停止する。
		public static int EnmDef_GetNth(VoidPtr pEnmKey, int iEnmDef, int index) {
			int iVal;
			if(!REG_open_nth_key_l(pEnmKey, index, out iVal, iEnmDef)) {	//REG_get_nth_value_l()ではない事に注意せよ。列挙型のレジストリ構造はpEnmKey⇒列挙型のキー⇒列挙型の値のキー⇒値の名前[,説明文]という構造である。
				throw new ApplicationException();	//列挙型の値のキーが無ければエラー。iEnmDef,又は,indexが間違っている。多分呼び出し側のバグ。
			}
			return iVal;
		}
		//-----------------------------------------------------------------------------
		//指定された値が、この列挙型における何番目の値であるかを逆引きする。この列挙型に属する値でなければ、(-1)を返す。
		public static int EnmDef_GetIdx(VoidPtr pEnmKey, int iEnmDef, int iVal) {
			//C言語版では高速化のためにバイナリサーチで検索していましたが、C#版ではリニアサーチにしました。
			//C#には、任意のシーケンスに対してバイナリサーチを行う組み込みの関数が無いみたい(?)だからです。
			int index, n = EnmDef_GetNum(pEnmKey, iEnmDef);
			for(index = 0; index < n; index++) {
				if(EnmDef_GetNth(pEnmKey, iEnmDef, index) == iVal) { return index; }
			}
			return -1;
		}
		//-----------------------------------------------------------------------------
		//列挙型の名前の文字列から、列挙型の値を逆引きする。指定された名前の文字列に一致する値が無かったら、(-1)を返す。
		public static int EnmDef_GetVal(VoidPtr pEnmKey, int iEnmDef, string pName) {
			int index, n = EnmDef_GetNum(pEnmKey, iEnmDef);
			for(index = 0; index < n; index++) {
				int iVal = EnmDef_GetNth(pEnmKey, iEnmDef, index);
				if(EnmDef_GetName(pEnmKey, iEnmDef, iVal) == pName) { return iVal; }
			}
			return -1;
		}
		//-----------------------------------------------------------------------------
		//この列挙型における、指定された値の次の値を取得する。
		//指定された値が最大値ならば、指定された値をそのまま返す。
		public static int EnmDef_IncVal(VoidPtr pEnmKey, int iEnmDef, int iVal) {
			int index = EnmDef_GetIdx(pEnmKey, iEnmDef, iVal);
			if(index == -1) { throw new ApplicationException(); }	//指定された値が、この列挙型に属する値でなければ、エラー停止する。
			if(index < EnmDef_GetNum(pEnmKey, iEnmDef) - 1) {
				iVal = EnmDef_GetNth(pEnmKey, iEnmDef, index + 1);
			}
			return iVal;
		}
		//-----------------------------------------------------------------------------
		//この列挙型における、指定された値の前の値を取得する。
		//指定された値が最小値ならば、指定された値をそのまま返す。
		public static int EnmDef_DecVal(VoidPtr pEnmKey, int iEnmDef, int iVal) {
			int index = EnmDef_GetIdx(pEnmKey, iEnmDef, iVal);
			if(index == -1) { throw new ApplicationException(); }	//指定された値が、この列挙型に属する値でなければ、エラー停止する。
			if(index > 0) {
				iVal = EnmDef_GetNth(pEnmKey, iEnmDef, index - 1);
			}
			return iVal;
		}
		//-----------------------------------------------------------------------------
		public static int EnmDef_GetVal_UseCompar(VoidPtr pEnmKey, int iEnmDef, string pName, StringComparer compar) {
			throw new NotImplementedException();
		}
		//-----------------------------------------------------------------------------
		public static StringComparer EnmDef_GetCanonicalNameCompar(VoidPtr pEnmKey, int iEnmDef) {
			throw new NotImplementedException();
		}
		//-----------------------------------------------------------------------------
		public static int EnmDef_IsSuitableNameCompar(VoidPtr pEnmKey, int iEnmDef, StringComparer compar) {
			throw new NotImplementedException();
		}
	}
}
