//--------------------------------------------------------------------------------------
//
// X-BASIC'
//	外部関数：カード関数
//
//--------------------------------------------------------------------------------------
// 外部関数の構造を持っている
// 基本的にX68用card.fnc(Oh!X 1990/5掲載)互換だが、若干拡張されている

#import "libs.h"
#include "XBiOScard.h"
#include "XBiOSx68.h"
#include "XBiOSg.h"
#include "fdef.h"
#include "support.h"
#import "FileControl2.h"

//---------------------------------------------------------------------------------------------
// 共通ワーク
// カード関数で必要なワーク

// パターンデータ
// X68の16色画面モードのドットデータそのものである
UByte cardPtrn[CARD_SIZE1*MAX_CARD];

//---------------------------------------------------------------------------------------------

// この外部関数のバージョンを返す
static RET_FUNC _F_version(SWord numFAC,FAC fac[])
{
	printFunc();
	fac[0].dl.cp[LL]=VERSION_XBIOSFUNCCARD;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//---------------------------------------------------------------------------------------------

static
int readCardFile(char *fname,UByte *buff,int buffsz)
{
	FILE *fp;
	NSString *path=getResourceOrSavedataPath(@(fname));
//	nslog2(@"path=%@",path);
	fname=nsStringTocString(path);
//	nslog2(@"path=%@",@(fname));
	fp=fopen(fname,"r");
	if (fp==NULL) {
//		// エラー処理
//		sprintf(buff,operationStatus.fenglish? "Can't read %s.":"%sが読み込めません",fname);
//		extraFunctionErrmes=buff;	// エラー出力側で@()してあるのでここは%sでok
		return (RET_FUNC_ERR);
	}
	fread(buff,buffsz,1,fp);
	fclose(fp);
	return (RET_FUNC_OK);
}

// int cardInit([userFile;str])
// パターンデータを読み込む
// 最初に呼び出す必要がある
static RET_FUNC _F_cardInit(SWord numFAC,FAC fac[])
{
	printFunc();

	int ret=0;
	if (fac[0].facType!=VOID_PARAM) { // 引数が省略されていない時
		// ユーザーファイルから全設定する
		if (readCardFile(bstrWithUTF8(fac[0].dl.bp[LL]),cardPtrn,CARD_SIZE1*MAX_CARD)!=RET_FUNC_OK) {
			ret=7;
		}
	} else {
		// 省略した時はデフォルトのカードデータを個別ファイルから読み取る
		//	UByte cardX68back[ CARD_SIZE1];
		//	UByte cardX68spade[CARD_SIZE1*MAX_TRUMP];
		//	UByte cardX68heart[CARD_SIZE1*MAX_TRUMP];
		//	UByte cardX68dia[  CARD_SIZE1*MAX_TRUMP];
		//	UByte cardX68club[ CARD_SIZE1*MAX_TRUMP];
		//	UByte cardX68joker[CARD_SIZE1];
		//	UByte cardX68user[ 残り];	// 使われないことも多いと思うけど、一応確保しておく
		UByte *cardX68back	=cardPtrn;
		UByte *cardX68spade	=&cardX68back[ CARD_SIZE1];
		UByte *cardX68heart	=&cardX68spade[CARD_SIZE1*MAX_TRUMP];
		UByte *cardX68dia	=&cardX68heart[CARD_SIZE1*MAX_TRUMP];
		UByte *cardX68club	=&cardX68dia[  CARD_SIZE1*MAX_TRUMP];
		UByte *cardX68joker	=&cardX68club[ CARD_SIZE1*MAX_TRUMP];
		if (readCardFile("back.dat"		,cardX68back	,CARD_SIZE1 		 )!=RET_FUNC_OK) ret=1;
		if (readCardFile("spade.dat"	,cardX68spade	,CARD_SIZE1*MAX_TRUMP)!=RET_FUNC_OK) ret=2;
		if (readCardFile("heart.dat"	,cardX68heart	,CARD_SIZE1*MAX_TRUMP)!=RET_FUNC_OK) ret=3;
		if (readCardFile("dia.dat"		,cardX68dia		,CARD_SIZE1*MAX_TRUMP)!=RET_FUNC_OK) ret=4;
		if (readCardFile("club.dat"		,cardX68club	,CARD_SIZE1*MAX_TRUMP)!=RET_FUNC_OK) ret=5;
		if (readCardFile("joker.dat"	,cardX68joker	,CARD_SIZE1			 )!=RET_FUNC_OK) ret=6;
	}
	fac[0].dl.l[LL]=ret;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// int cardCalcNo(suit;int,no;int)
// スートと数から通しのカード番号を得る
// suite=SUITE_* , no=1〜13
// 番号がおかしいときは常に0=裏面を返す
// 裏面、ジョーカー、ユーザーカードは指定しないこと
// 番号がおかしいときは裏面を返す
static RET_FUNC _F_cardCalcNo(SWord numFAC,FAC fac[])
{
	printFunc();
	
	int suit=(int)fac[0].dl.l[LL];
	int   no=(int)fac[1].dl.l[LL];
	
	int ret=0; // 番号がおかしい時のため
	switch (suit) {
	    case SUIT_SPADE:
		case SUIT_HEART:
		case SUIT_DIA:
		case SUIT_CLUB:
			if (no>=1 && no<=MAX_TRUMP) {
				ret=(suit*MAX_TRUMP+no);
			}
		default:
			break;
	}
	fac[0].dl.l[LL]=ret;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// カード番号のパターンのアドレスを返す
UByte *cardGetPutSub(int cno)
{
	return &cardPtrn[cno*CARD_SIZE1];
}


// cardPut(x;int,y;int,cno;int,fdouble;int)
// 指定番号のカードを表示する
// fdoubleがiOS拡張
// 基本的に固定データなので予め変換しておく手もあるが、以下の理由によりリアルタイム変換する
// (1)データを少しでも圧縮した状態にしておきたい(小サイズ)
// (2)一応ユーザー書き換えが可能である
// (3)横倍表示をするため(fdouble=YES)
static RET_FUNC _F_cardPut(SWord numFAC,FAC fac[])
{
	printFunc();
	
	int i=0;
	int x		=(int)fac[i++].dl.l[LL];
	int y		=(int)fac[i++].dl.l[LL];
	int cno		=(int)fac[i++].dl.l[LL];
	int fdouble	=basic2cYESNO(fac[i++].dl.l[LL]);

	// X68パターンを得る
	UByte ptrnX68[CARD_SIZE1];
	UByte *base=cardGetPutSub(cno);
	for (i=0;i<CARD_SIZE1;i++) {
		ptrnX68[i]=*base++;
	}

	// X68パターンは、4ビット1ドットで、GRBI順
	// 0000
	// 0001	I
	// 0010	B
	// 0011	BI
	// 0100	R
	// 0101	RI
	// 0110	RB
	// 0111	RBI
	// 1000	G
	// 1001	GI
	// 1010	GB
	// 1011	GBI
	// 1100	GR
	// 1101	GRI
	// 1111	GRBI
	
	// X68->iOS変換
	ULong ptrniOS[CARD_SIZE1*2*2];	// 横2ドットを1ドットずつにする＊縦横倍対応のため X-BASICのint
	ptrn16X68toiOS(CARD_SIZE1,ptrnX68,ptrniOS,fdouble,NO);
	 
	// パターンをビットマップに描画する
	int wx=CARD_WX;
	if (fdouble) wx*=2;
	_F_bitmapPatternSub(x,y,wx,CARD_WY,(UByte *)ptrniOS);
	
	_F_bitmapImgLoadSub(0,0,0,0);

	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// int cardGet(cno;int,ptrn();char)
// X68パターンを返す
static RET_FUNC _F_cardGet(SWord numFAC,FAC fac[])
{
	printFunc();
	
	int i=0;
	int cno=(int)fac[i++].dl.l[LL];
	SWord   size1;
	uwYouso youso;
	UByte *ptrn=(UByte *)getDim1FromFAC(fac,i++,&size1,&youso);
	if (ptrn==NULL) { // 1次元でない
		return (RET_FUNC_ERR);
	}
	if (cno<0||cno>=MAX_CARD) {
		setExternalFuncErrmes("カード番号が異常です","Card No. is illegal.");
		return (RET_FUNC_ERR);
	}
	if (size1!=1) {
		// 1要素サイズが違う
		setExternalFuncErrmes("要素型が異なります","Array's type is illegal.");
		return (RET_FUNC_ERR);
	}
	if (youso<CARD_SIZE1) {
		// 要素数が足りない
		setExternalFuncErrmes("配列の要素数が足りません","Array's elements are not enough.");
		return (RET_FUNC_ERR);
	}

	UByte *base=cardGetPutSub(cno);
	for (i=0;i<CARD_SIZE1;i++) {
		*ptrn++=*base++;
	}

	fac[0].dl.l[LL]=0;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

// int cardSet(cno;int,ptrn();char)
// X68パターンを設定する
static RET_FUNC _F_cardSet(SWord numFAC,FAC fac[])
{
	printFunc();
	
	int i=0;
	int cno=(int)fac[i++].dl.l[LL];
	SWord   size1;
	uwYouso youso;
	UByte *ptrn=(UByte *)getDim1FromFAC(fac,i++,&size1,&youso);
	if (ptrn==NULL) { // 1次元でない
		return (RET_FUNC_ERR);
	}
	if (cno<0||cno>=MAX_CARD) {
		setExternalFuncErrmes("カード番号が異常です","Card No. is illegal.");
		return (RET_FUNC_ERR);
	}
	if (size1!=1) {
		// 1要素サイズが違う
		setExternalFuncErrmes("要素型が異なります","Array's type is illegal.");
		return (RET_FUNC_ERR);
	}
	if (youso<CARD_SIZE1) {
		// 要素数が足りない
		setExternalFuncErrmes("配列の要素数が足りません","Array's elements are not enough.");
		return (RET_FUNC_ERR);
	}
	
	UByte *base=cardGetPutSub(cno);
	for (i=0;i<CARD_SIZE1;i++) {
		*base++=*ptrn++;
	}
	
	fac[0].dl.l[LL]=0;
	fac[0].facType=FACTYPE_RETURN;
	return (RET_FUNC_OK); // OK
}

//---------------------------------------------------------------------------------------------
// インフォメーションテーブル (5.2.1章)
//---------------------------------------------------------------------------------------------

// 関数名テーブル(トークンテーブル)
static const char *iOScardTokens[]={
	"cardInit",
	"cardCalcNo",
	"cardPut",
	"cardGet",
	"cardSet",
	// バージョン
	"versionXBiOSCard$",
	// end of table
	NULL,
};
				
// 実行アドレステーブル
static FUNC_EXEC iOScardFuncExec[]={
	// Cの標準関数名と重複させないよう_F_を付ける
	{_F_cardInit},
	{_F_cardCalcNo},
	{_F_cardPut},
	{_F_cardGet},
	{_F_cardSet},
	// バージョン
	{_F_version},
	// end of table
	{NULL},
};

//------------------------------
// パラメーターテーブル
// (1)種類別定義
// 1関数の引数は最大MAX_PARAM個

static const uwPARAMTYPE p_cardInit[]={
	STR_OMT,
	STR_OMT,
	STR_OMT,
	STR_OMT,
	STR_OMT,
	STR_OMT,
	INT_RET,
};

static const uwPARAMTYPE p_cardCalcNo[]={
	INT_VAL,
	INT_VAL,
	INT_RET,
};

static const uwPARAMTYPE p_cardPut[]={
	INT_VAL,
	INT_VAL,
	INT_VAL,
	INT_VAL,
	VOID_RET,
};

static const uwPARAMTYPE p_cardGet[]={
	INT_VAL,
	ARRAY1_CHAR,
	INT_RET,
};
#define p_cardSet	p_cardGet

static const uwPARAMTYPE p_version[]={
	STR_RET,
};

//------------------------------
// パラメーターテーブル
// (2)関数別定義

static
const
uwPARAMTYPE *iOScardParams[]={
	p_cardInit,
	p_cardCalcNo,
	p_cardPut,
	p_cardGet,
	p_cardSet,
	// バージョン
	p_version	,
	// end of table
	NULL,
};

//-------------

// この中の関数の初期化処理
static void _Frun(void)
{
	printFunc();
}

// この中の関数の終了処理
static void _Fend(void)
{
	printFunc();
}

// インフォメーションテーブル
const
INFORMATION_TABLE	InfoCardFuncs={
	#ifdef FUNC_DEBUG
	"iOS X68 Card functions",
	#endif
	returnOnly,	// Finit
	_Frun,		// Frun
	_Fend,		// Fend
	returnOnly,	// Fexit
	returnOnly,	// Fbreak
	NULL,		// FctrlD;未使用
	NULL,		// 予約1
	NULL,		// 予約2
	//
	iOScardTokens,
	iOScardParams,
	iOScardFuncExec
};

//---------------------------------------------------------------------------------------------
