#include "app.h"
/****************************************************************************
 *	ローカル変数
 ****************************************************************************/
//{{2016/08/21追加:'-e'オプションを追加しました。
//'-e'オプションのサブオプション
enum {
	OPT_E_HITVAL,		//-ehitval	当選値(hitVal)を指数表現と見なして表示する。
	OPT_E_COLUMN_ID,	//-ecolumn_id	抽選列id(column_id)を指数表現と見なして表示する。
	OPT_E_WEIGHT,		//-eweight	抽選値(weight)を指数表現と見なして表示する。
	//
	OPT_E_ALL,		//-eall		上記の全てを指数表現と見なして表示する。
};
static const char* const opt_e_tokens[]={
	"hitval",
	"column_id",
	"weight",
	//
	"all",
NULL};//終端
static int opt_e;	//(1<<OPT_E_HITVAL),(1<<OPT_E_COLUMN_ID),(1<<OPT_E_ALL)の、0個以上の組み合わせ
//}}2016/08/21追加:'-e'オプションを追加しました。
/****************************************************************************
 *	ローカル関数宣言
 ****************************************************************************/
__declspec(noreturn) static void usage();
static void dumpLotTbl(int indent, const int* TBL_LotTblNo/*[LotTblNo_Max+1]*/);
/****************************************************************************
 *	
 ****************************************************************************/
int main(int argc, char* argv[]) {
	FILE* fp;
	void* buf;
	int opt, len;
	//コマンドラインオプションを処理する。
	opterr = 0; //オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。
	while((opt = getopt(argc, argv, "e::h")) != -1) {
		switch(opt) {
//{{2016/08/21追加:'-e'オプションを追加しました。
		case 'e':
			if(optarg) {
				char *optionp = optarg, *valuep;
				while(*optionp) {
					int subopt = getsubopt(&optionp, (char* const*)opt_e_tokens, &valuep);
					if(valuep) { usage(); }
					switch(subopt) {
					case OPT_E_HITVAL:	//-ehitval	当選値(hitVal)を指数表現と見なして表示する。
					case OPT_E_COLUMN_ID:	//-ecolumn_id	抽選列id(column_id)を指数表現と見なして表示する。
					case OPT_E_WEIGHT:	//-eweight	抽選値(weight)を指数表現と見なして表示する。
						opt_e |= (1<<subopt);
						break;
					case OPT_E_ALL:		//-eall		上記の全てを指数表現と見なして表示する。
						opt_e |= -1;
						break;
					default:
						usage();
					}
				}
			} else {
				opt_e |= (1<<OPT_E_WEIGHT);	//-e		-eweightと同じです。(-eallと同じではない事に注意して下さい。指数表現を格納するのは抽選値だけである事がほとんどだと思うので、-eのデフォルトは-eweightと同じとする事にしました。)
			}
			break;
//}}2016/08/21追加:'-e'オプションを追加しました。
		case 'h':
		default:
			usage();
		}
	}
	//抽選テーブルのバイナリデータを読み込む。
	if(optind != (argc - 1)) { usage(); }	//引数の数が不正
	fp = fopen(argv[optind], "rb");
//{{2016/05/28追加:ファイルオープンエラーを検査し忘れていたバグを修正しました。
	if(!fp) { error(EXIT_FAILURE, errno, "%s が開けません。", argv[optind]); }
//}}2016/05/28追加:ファイルオープンエラーを検査し忘れていたバグを修正しました。
	fseek(fp, 0, SEEK_END);
	len = ftell(fp);
	rewind(fp);
	buf = malloc(len);
	if(!buf) { DIE(); }	//メモリ不足
	fread(buf, 1, len, fp);
	fclose(fp);
	//抽選テーブルをダンプする。
	dumpLotTbl(0, buf);
	return EXIT_SUCCESS;
}
/*---------------------------------------------------------------------------*/
__declspec(noreturn) static void usage() {
	fprintf(stderr, "dLotTblD - 抽選テーブル逆コンパイラ (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2015-2016 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "USAGE:\n");
	fprintf(stderr, "  dLotTblD [option] LotTbl.bin\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "OPTIONS:\n");
	fprintf(stderr, "  -ehitval     当選値を、指数表現と見なして表示します。\n");
	fprintf(stderr, "  -ecolumn_id  抽選列idを、指数表現と見なして表示します。\n");
	fprintf(stderr, "  -eweight     抽選値を、指数表現と見なして表示します。\n");
	fprintf(stderr, "  -eall        '-ehitval,column_id,weight'と同じです。\n");
	fprintf(stderr, "  -e           '-eweight'と同じです。\n");
	fprintf(stderr, "  -h           使い方を表示します。\n");
	exit(EXIT_FAILURE);
}
/*--------------------------------------------------------------------------*/
static void dumpLotTbl(int indent, const int* TBL_LotTblNo/*[LotTblNo_Max+1]*/) {
	const int nLotTblNo = TBL_LotTblNo[0];								//(抽選表番号の最大値+1)を取得する。
	int iLotTblNo;
	for(iLotTblNo = 1; iLotTblNo < nLotTblNo; iLotTblNo++) {
		ST_Worksheet* wsHead = Worksheet_new();
		ST_Worksheet* wsBody = Worksheet_new();
		ST_Worksheet_Iterator it;
		const unsigned short* pLotTbl = (const unsigned short*)&TBL_LotTblNo[nLotTblNo];	//抽選表データへのポインタを求める。(抽選表アドレステーブルの直後に抽選表データを配置する前提)
		const unsigned short* table = &pLotTbl[TBL_LotTblNo[iLotTblNo]];			//抽選表へのポインタを求める。
		const int table_size = *table++;							//抽選表の列数
		const int id_size    = *table++;							//抽選列のid行数
		int column_size, i_column, i_row, i_id, id, hitval, weight;
		printf(":`%05u\n", iLotTblNo);								//出力:抽選表id		リコンパイルした時に、iLotTblNoの昇順で元の抽選表idに一致するよう、0埋めして5桁に揃えておく。こうしないと、データ列の抽選値として抽選表idを入れてリンクしている部分が、リコンパイルした時にずれてしまう。
		for(i_column = 0; i_column < table_size; i_column++) {
			for(i_id = 0; i_id < id_size; i_id++) {
				id = *table++;
				Worksheet_set_l(wsHead, id, i_id, i_column, -1);			//(抽選列id行番号,列番号)⇒抽選列id
			}
			column_size = *table++;								//抽選列の要素数
			for(i_row = 0; i_row < column_size; i_row++) {
				hitval = *table++;							//当選値
				weight = *table++ + 1;							//抽選値
				Worksheet_set_l(wsBody, weight, hitval, i_column, -1);			//(当選値,列番号)⇒抽選値
			}
		}
//{{2016/08/21削除:2016/07/18に、/clip/clipwkst.hの大幅な変更を行い、Worksheet_sort()を廃止した事に伴い、当ツールもWorksheet_sort()の呼び出しを削除しました。
//		Worksheet_sort(wsHead);
//		Worksheet_sort(wsBody);
//}}2016/08/21削除:2016/07/18に、/clip/clipwkst.hの大幅な変更を行い、Worksheet_sort()を廃止した事に伴い、当ツールもWorksheet_sort()の呼び出しを削除しました。
		for(i_id = 0; i_id < id_size; i_id++) {
			printf("id", hitval);								//出力:'id'
			for(i_column = 0; i_column < table_size; i_column++) {
				id = Worksheet_get_l(wsHead, i_id, i_column, -1);			//(抽選列id行番号,列番号)
//{{2016/08/21変更:'-e'オプションを追加しました。
//				printf("\t,%u", id);							//出力:抽選列id
//↓2016/08/21変更:'-e'オプションを追加しました。
				//'-ecolumn_id'オプションが指定されていたら…
				if(opt_e & (1<<OPT_E_COLUMN_ID)) {
					//抽選列idを、指数表現と見なして表示します。
					printf("\t,%u", Exp10_Decode(id));				//出力:抽選列id		指数表現
				//'-ecolumn_id'オプションが指定されていなければ…
				} else {
					//抽選列idを、そのまま表示します。
					printf("\t,%u", id);						//出力:抽選列id
				}
//}}2016/08/21変更:'-e'オプションを追加しました。
			}
			printf("\n");
		}
		for(hitval = Worksheet_first_l(wsBody, &it, -1);
		    hitval != -1;
		    hitval = Worksheet_next(&it)) {
//{{2016/08/21変更:'-e'オプションを追加しました。
//			printf("%u", hitval);								//出力:当選値
//↓2016/08/21追加:'-e'オプションを追加しました。
			//'-ehitval'オプションが指定されていたら…
			if(opt_e & (1<<OPT_E_HITVAL)) {
				//当選値を、指数表現と見なして表示します。
				printf("%u", Exp10_Decode(hitval));					//出力:当選値		指数表現
			//'-eweight'オプションが指定されていなければ…
			} else {
				//当選値を、そのまま表示します。
				printf("%u", hitval);							//出力:当選値
			}
//}}2016/08/21追加:'-e'オプションを追加しました。
			for(i_column = 0; i_column < table_size; i_column++) {
				weight = Worksheet_get_l(wsBody, hitval, i_column, -1);			//(当選値,列番号)
//{{2016/08/21追加:'-e'オプションを追加しました。
//				printf("\t,%u", weight);						//出力:抽選値
//↓2016/08/21追加:'-e'オプションを追加しました。
				//'-eweight'オプションが指定されていたら…
				if(opt_e & (1<<OPT_E_WEIGHT)) {
					//指数表現としてデコード可能な値でなければ…
					// - 指数表現として格納されていない値を、指数表現として表示しようとした場合に、問題が生じる可能性が有る。
					//   指数表現の範囲は0〜65535であるが、抽選値の範囲は0〜65536であり、65536を指数表現としてデコードしようとすると、Exp10_Decode()がエラー停止してしまう。
					//   この問題を回避するために、65536ならば'#N/A'を表示する事にした。
					if(weight == 65536) {
						//'#N/A'を表示します。
						printf("\t,#N/A");					//出力:抽選値		指数表現として無効な値
					//指数表現としてデコード可能な値ならば…
					} else {
						//抽選値を、指数表現と見なして表示します。
						printf("\t,%u", Exp10_Decode(weight));			//出力:抽選値		指数表現
					}
				//'-eweight'オプションが指定されていなければ…
				} else {
					//抽選値を、そのまま表示します。
					printf("\t,%u", weight);					//出力:抽選値
				}
//}}2016/08/21追加:'-e'オプションを追加しました。
			}
			printf("\n");
		}
		printf("\n");
	}
}
