//--------------------------------------------------------------------------------------
//
// X-BASIC' v3.00
//	バッファー制御
//		従来のチェインバッファーに替わるもの
//		クラスで実装すべきだろうけど、コア内で使うのであえてC関数で実装
//
//--------------------------------------------------------------------------------------

#include "fdef.h"
#include "XB.h"
#import "bufferCtrl.h"
#import "malloc2.h"

//#define DBG_Func()		nslog(@"%s",__FUNCTION__)

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

/// デフォルト比較関数
/// @param data1 バッファー内データ
/// @param data0 比較対象データ
BOOL defCmpData(void *data1,void *data0)
{
	// 常に不一致
	return NO;
}

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

/// 初期化
/// @param addStep	バッファーを増やすときの増分(何データ分入れられるように増やすか)
/// @param size1	１要素のサイズ
void _initBuffer(BUFF_CTRL *ctrl,int addStep,int size1)
{
	DBG_Func();
	nslog(@"ctrl=%p",ctrl);
	
	ctrl->addStep	=addStep;
	ctrl->sizeOfData=size1;
	//
	ctrl->enableToAddIn1Block=0;
	ctrl->buffer	=NULL;			// 最初登録時にバッファーが確保される=ここではまだ確保しない
	ctrl->blocks	=0;
	ctrl->cnt		=0;
	//
	ctrl->cmpData	=defCmpData;	// 初期比較関数
	ctrl->printData	=NULL;			// 初期は表示関数なし
}


void _initBufferWithPrintData(BUFF_CTRL *ctrl,int addStep,int size1,void (*printData)(void *data))
{
	DBG_Func();
	_initBuffer(ctrl, addStep, size1);
	ctrl->printData=printData;
}


void closeBuffer(BUFF_CTRL *ctrl)
{
	DBG_Func();
	if (ctrl->buffer!=NULL) {
		free2(ctrl->buffer);
	} // else 実バッファー登録がないままに終了した時
}

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

#ifdef DEBUG
void dumpBuffer(BUFF_CTRL *ctrl,BOOL fdumpInBuffer)
{
	DBG_Func();
	nslog(@"登録バッファー=%p"								,ctrl->buffer);
	nslog(@"確保済みブロック数=%d"							,ctrl->blocks);
	nslog(@"現在のブロック(今回の増分)での残り格納可能数=%d"	,ctrl->enableToAddIn1Block);
	nslog(@"登録済み要素数=%d"								,ctrl->cnt);
	nslog(@"最大要素数=%d"								,ctrl->maxCnt);
	// 外部で設定
	nslog(@"バッファー増分単位;何要素入れられるようにするか=%d"	,ctrl->addStep);
	nslog(@"登録する1要素のサイズ=%d"						,ctrl->sizeOfData);

	if (fdumpInBuffer) {
		// バッファ内容もダンプするとき
		if (ctrl->printData!=NULL) {
			for (int i=0;i<ctrl->cnt;i++) {
				void *data=&ctrl->buffer[i*ctrl->sizeOfData];
				printf("[%d]",i);
				ctrl->printData(data);
			}
		}
	}
}
#endif

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

/// 値を持つデータを探す
/// @param [in] ctrl	制御構造体BUFF_CTRL
/// @param [in] data	比較対象
/// @return !=NULL;得た値のアドレス , NULL=なし
void *searchValueFromBuffer(BUFF_CTRL *ctrl,void *data0)
{
	DBG_Func();
	for (int i=0;i<ctrl->cnt;i++) {
		// 比較
		void *data1=&ctrl->buffer[ctrl->sizeOfData*i];
		if (ctrl->cmpData(data1,data0)) {
			// 一致
			nslog(@"発見");
			return (data1);
		}
	}
	// 存在しない
	return (NULL);
}

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

/// 値を得る；アドレスリターン型
/// @param [in] ctrl	制御構造体BUFF_CTRL
/// @param [in] point	読み出し位置
/// @return !=NULL;得た値のアドレス , NULL=なし
/// @note アドレスはバッファー内部のアドレスで境界整合などは考慮されてないので、そこを直接アクセスすると落ちる可能性がある
void *getValueFromBuffer(BUFF_CTRL *ctrl,int point)
{
	DBG_Func();
	if (point<0||point>=ctrl->cnt) {
		DBG_printsn("存在しない");
		return (NULL);
	}
	return &ctrl->buffer[ctrl->sizeOfData*point];
}


/// 値を得る；直接コピー型
/// @param [in] ctrl	制御構造体BUFF_CTRL
/// @param [in] point	読み出し位置
/// @param [out] data	データを返すワーク
/// @param [in] size1	サイズ
/// @return YES=値がない , NO=正常終了
/// @note データは与えられたワークにコピーされるので、dataさえ境界性号が正しければ問題ない
BOOL getValueFromBufferByCopy(BUFF_CTRL *ctrl,int point,void *data,int size)
{
	DBG_Func();
	if (point<0||point>=ctrl->cnt) {
		DBG_printsn("存在しない");
		return (YES);
	}
	mmemcpy(data,&ctrl->buffer[ctrl->sizeOfData*point],size);
	return NO;
}

/// 指定位置のバッファー内アドレスを返す
/// @param [in] ctrl	制御構造体BUFF_CTRL
/// @param [in] point	読み出し位置
/// @return バッファー内アドレス
void *getValueAdrs(BUFF_CTRL *ctrl,int point)
{
	DBG_Func();
	if (point<0||point>=ctrl->cnt) {
		DBG_printsn("存在しない");
		return (NULL);
	}
	return &ctrl->buffer[ctrl->sizeOfData*point];
}

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

/// 値追加
/// @param [in] ctrl	制御構造体BUFF_CTRL
/// @param [in] data	書き込むデータ
/// @return	書き込み開始アドレス
void *addValueForBuffer(BUFF_CTRL *ctrl,void *data)
{
	DBG_Func();
	
	// チェインバッファーへの記録
#if COMPILE_MODE<2 // Distributionの時は外す
	printf("バッファーへの記録[%d]:",ctrl->cnt);
	if (ctrl->printData!=NULL) {
		ctrl->printData(data);
	}
#endif
	
	if (ctrl->enableToAddIn1Block==0) {
		nslog(@"バッファー追加");
		// 現在のバッファーには入りきらないので増やす
		ctrl->blocks++; // ブロック数+1
		ctrl->maxCnt+=ctrl->addStep; // 格納可能要素数を増加
		ctrl->buffer=realloc2(ctrl->buffer,ctrl->sizeOfData*ctrl->maxCnt); // バッファーを確保しなおし
		ctrl->enableToAddIn1Block=ctrl->addStep; // 追加したブロックへの追加可能要素数
#ifdef DEBUG
		dumpBuffer(ctrl, NO);
#endif
	}
	void *adrs=&ctrl->buffer[ctrl->sizeOfData*ctrl->cnt]; // オフセットでアクセしているので先頭アドレスをreallocしても問題ない
	mmemcpy(adrs,data,ctrl->sizeOfData);
	ctrl->cnt++; // 格納済み要素数＋１
	ctrl->enableToAddIn1Block--; // このブロックへの格納可能数-1
	
	// 書き込み開始アドレスを返す
	return adrs;
}

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

/// 値追加；重複排除付き
/// @param [in] ctrl	制御構造体BUFF_CTRL
/// @param [in] data	書き込むデータ
/// @return YES=重複定義あり , NO=設定完了
BOOL addValueForBufferNoRedundant(BUFF_CTRL *ctrl,void *data)
{
	DBG_Func();

	if (searchValueFromBuffer(ctrl,data)!=NULL) {
		nslog(@"重複定義");
		return (YES);
	}
	// 重複はないので追加
	addValueForBuffer(ctrl,data);
	return (NO); // 正常終了
}

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

/// 値追加(可変サイズ)
/// dataのサイズがsizeOfDataの倍数であるとき、一気に書き込む
/// @param [in] ctrl	制御構造体BUFF_CTRL
/// @param [in] data	書き込むデータ
/// @param [in] size	書き込みサイズ ; sizeof(data)>=sizeOfDataで必ずsizeOfDataの倍数であること
/// @return	書き込み開始アドレス
void *addValueForBufferWithSize(BUFF_CTRL *ctrl,void *data,int size)
{
	DBG_Func();

	void *adrs=NULL;
	
	size/=ctrl->sizeOfData; // sizeOfData単位での書き込み回数
	for (int i=0;i<size;i++) {
		void *adrs0=addValueForBuffer(ctrl, data);
		if (adrs==NULL) adrs=adrs0;
		data+=ctrl->sizeOfData;
	}
	
	// 書き込み先頭アドレスを返す
	return adrs;
}

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