/*
 *-----------------------------------------------------------------------------
 *  FILE: backup.c
 *
 *      Copyright(c) 1998 SEGA System R&D Dept.
 *
 *  PURPOSE:
 *
 *      バックアップライブラリサンプル(動的メモリ確保版)
 *
 *  DESCRIPTION:
 *
 *  AUTHOR(S):
 *
 *      1997/9/21  S.Uchida Ver.0.00
 *
 *  MOD HISTORY:
 *
 *-----------------------------------------------------------------------------
 */

#include <shinobi.h>
#include "backup.h"

/*===============================================================*/
/* 対応するバックアップRAMの最大容量                             */
/*===============================================================*/

#define MAX_CAPS BUD_CAPACITY_1MB


/*===============================================================*/
/* 対応するバックアップRAMのドライブ数                           */
/*===============================================================*/

#define MAX_DRIVES 8
#define USE_DRIVES BUD_USE_DRIVE_ALL


/*===============================================================*/
/* バックアップRAMの状態を格納しておく構造体                     */
/* (backup.h を参照)                                             */
/*===============================================================*/

BACKUPINFO gBupInfo[8];



/*===============================================================*/
/*      スタティック関数のプロトタイプ宣言                       */
/*===============================================================*/

static Sint32 BupComplete(Sint32 drive, Sint32 op, Sint32 stat, Uint32 param);
static Sint32 BupProgress(Sint32 drive, Sint32 op, Sint32 count, Sint32 max);
static void BupInitCallback(void);
static void ClearInfo(Sint32 drive);


/*===============================================================*/
/*      バックアップライブラリ初期化                             */
/*      動的メモリ確保をするため、ワークアドレスにはNULLを指定   */
/*===============================================================*/

void BupInit(void)
{
	memset(gBupInfo, 0, sizeof(gBupInfo));
	buInit(MAX_CAPS, USE_DRIVES, NULL, BupInitCallback);
}


/*===============================================================*/
/*      バックアップライブラリ終了                               */
/*===============================================================*/

void BupExit(void)
{
	do {} while (buExit() != BUD_ERR_OK);
}


/*===============================================================*/
/*      バックアップRAMの状態を取得                              */
/*===============================================================*/

const BACKUPINFO* BupGetInfo(Sint32 drive)
{
	return (const BACKUPINFO*)&gBupInfo[drive];
}


/*===============================================================*/
/*      ファイルのロード                                         */
/*===============================================================*/

Sint32 BupLoad(Sint32 drive, const char* fname, void* buf)
{
	return buLoadFile(drive, fname, buf, 0);
}


/*===============================================================*/
/*      ファイルのセーブ                                         */
/*===============================================================*/

enum {
	Sunday = 0,
	Monday,
	Tuesday,
	Wednesday,
	Thursday,
	Friday,
	Saturday
};

static const BUS_TIME gBupTime = {
	1998, 12, 31,	/* 年月日 */
	23, 59, 59,		/* 時分秒 */
	Thursday,		/* 曜日   */
};

Sint32 BupSave(Sint32 drive, const char* fname, void* buf, Sint32 nblock)
{
	return buSaveFile(drive, fname, buf, nblock, (BUS_TIME *) &gBupTime,
							BUD_FLAG_VERIFY | BUD_FLAG_COPY(0));
}


/*===============================================================*/
/*      ファイルの削除                                           */
/*===============================================================*/

Sint32 BupDelete(Sint32 drive, const char* fname)
{
	return buDeleteFile(drive, fname);
}

/*===============================================================*/
/*      ワークの確保とマウント                                   */
/*      この処理が終了し、マウントコールバックが返ってから       */
/*      今までどおりファイルアクセスが可能になります             */
/*===============================================================*/

void BupMount(Sint32 drive)
{
	BACKUPINFO* info;

	info = &gBupInfo[drive];

	if (info->Work) return;		/* すでにマウント済み */

	info->Work = syMalloc(info->WorkSize);

	buMountDisk(drive, info->Work, info->WorkSize);
}

/*===============================================================*/
/*      アンマウント                                             */
/*      これ以降そのドライブにはアクセスできません               */
/*      再びアクセスしたい場合は、もう一度ワークの確保と         */
/*      マウントを行ってください                                 */
/*      buUnmount()使用上の注意(※重要)                          */
/*       ・BUD_OP_UNMOUNTコールバックは発生しません              */
/*       ・必ずbuStat()でそのドライブにアクセスが行われていない  */
/*         ことを確認してからアンマウントしてください            */
/*       ・直後にワークを開放しても問題ありません                */
/*===============================================================*/

void BupUnmount(Sint32 drive)
{
	BACKUPINFO* info;
	Sint32 err;

	info = &gBupInfo[drive];

	if (info->Work == NULL) return;	/* マウントされていない */

	/* そのドライブがアクセス中であるなら、アンマウントしたり */
	/* ワークを開放してはならない                             */
	if (buStat(drive) == BUD_STAT_READY) {
		buUnmount(drive);
		syFree(info->Work);
		ClearInfo(drive);
	}
}

static void ClearInfo(Sint32 drive)
{
	BACKUPINFO* info;

	info = &gBupInfo[drive];
	info->ProgressCount = 0;
	info->ProgressMax = 0;
	info->Operation = 0;
	info->Ready = FALSE;
	info->IsFormat = FALSE;
	info->Work = NULL;
	memset(&info->DiskInfo, 0, sizeof(BUS_DISKINFO));
}

/*===============================================================*/
/*      エラーコードを文字列に変換                               */
/*===============================================================*/

const char* BupGetErrorString(Sint32 err)
{
	switch (err) {
		case BUD_ERR_OK:				return "OK\0";
		case BUD_ERR_BUSY:				return "BUSY\0";
		case BUD_ERR_INVALID_PARAM:		return "INVALID PARAMETER\0";
		case BUD_ERR_ILLEGAL_DISK:		return "ILLEGAL DISK\0";
		case BUD_ERR_UNKNOWN_DISK:		return "UNKNOWN DISK\0";
		case BUD_ERR_NO_DISK:			return "NO DISK\0";
		case BUD_ERR_UNFORMAT:			return "UNFORMAT\0";
		case BUD_ERR_DISK_FULL:			return "DISK FULL\0";
		case BUD_ERR_FILE_NOT_FOUND:	return "FILE NOT FOUND\0";
		case BUD_ERR_FILE_EXIST:		return "FILE EXIST\0";
		case BUD_ERR_CANNOT_OPEN:		return "CANNOT OPEN\0";
		case BUD_ERR_CANNOT_CREATE:		return "CANNOT CREATE\0";
		case BUD_ERR_EXECFILE_EXIST:	return "EXECUTABLE FILE EXIST\0";
		case BUD_ERR_ACCESS_DENIED:		return "ACCESS DENIED\0";
		case BUD_ERR_VERIFY:			return "VERIFY ERROR\0";
		default:						return "GENERIC ERROR\0";
	}
}


/*===============================================================*/
/*      オペレーションコードを文字列に変換                       */
/*===============================================================*/

const char* BupGetOperationString(Sint32 op)
{
	switch (op) {
		case BUD_OP_CONNECT:		return "CONNECTED\0";
		case BUD_OP_MOUNT:			return "MOUNTED\0";
		case BUD_OP_UNMOUNT:		return "UNMOUNTED\0";
		case BUD_OP_FORMATDISK:		return "FORMATDISK\0";
		case BUD_OP_DELETEFILE:		return "DELETEFILE\0";
		case BUD_OP_LOADFILE:		return "LOADFILE\0";
		case BUD_OP_SAVEFILE:		return "SAVEFILE\0";
		default:					return "UNKNOWN OPERATION\0";
	}
}


/*===============================================================*/
/*      コールバック関数                                         */
/*===============================================================*/

/*
** 初期化終了コールバック関数
*/

static void BupInitCallback(void)
{
	Sint32 i;

	/* 完了、経過コールバック関数を設定する */
	buSetCompleteCallback(BupComplete);
	buSetProgressCallback(BupProgress);
}


/*
** 完了コールバック関数
*/

static Sint32 BupComplete(Sint32 drive, Sint32 op, Sint32 stat, Uint32 param)
{
	BACKUPINFO* info;
	Sint32 ret;


	info = &gBupInfo[drive];

	switch (op) {
		/* バックアップRAMが接続された */
		case BUD_OP_CONNECT:
			info->Connect = TRUE;
			info->WorkSize = BUM_WORK_SIZE(stat, 1);
			info->Capacity = stat;
			break;
		/* バックアップRAMがマウントされた */
		case BUD_OP_MOUNT:
			if (stat == BUD_ERR_OK) {
				info->Ready = TRUE;
				ret = buGetDiskInfo(drive, &info->DiskInfo);
				if (ret == BUD_ERR_OK) {
					info->IsFormat = TRUE;
				}
				/* エラー状態をクリア */
				info->LastError = BUD_ERR_OK;
			}
			break;
		/* バックアップRAMが取り外された */
		case BUD_OP_UNMOUNT:
			if (info->Work) syFree(info->Work);
			ClearInfo(drive);
			info->Connect = FALSE;
			break;
		default:
			/* エラー状態を格納 */
			info->LastError = stat;

			/* 情報を更新する */
			buGetDiskInfo(drive, &info->DiskInfo);
	}

	/* オペレーションをクリア */
	info->Operation = 0;

	return BUD_CBRET_OK;
}


/*
** 経過コールバック関数
*/

static Sint32 BupProgress(Sint32 drive, Sint32 op, Sint32 count, Sint32 max)
{
	BACKUPINFO* info;

	info = &gBupInfo[drive];

	/* 経過状態、オペレーションコードを格納 */
	info->ProgressCount = count;
	info->ProgressMax = max;
	info->Operation = op;

	return BUD_CBRET_OK;
}



/******************************* end of file *******************************/
