/*
 ******************************************************************************
 *              
 *      セーブ情報の処理
 *              
 *      $Id: saveManager.c,v 1.1 2003/05/30 21:25:28 tong Exp $
 ******************************************************************************
 */
#include "saveManager.h"
/*
 ******************************************************************************
 *
 *     EEPROMセーブ情報の処理は, EEPROMからバッファに読み込まれてきたセーブ
 *   情報を'○'マークの関数群によって操作し, その結果をEEPROMに書き込む一連
 *   の処理によって行われる。
 *
 *  ○ EEPROMセーブのオプション情報操作について
 *
 *     get_soundMode()     : サウンドモードを得る。
 *     put_soundMode(m)    : サウンドモード(m)を設定する。
 *                           (m)は MONAURAL/STEREO/HEADPHONE の何れかを設定。
 *     is_monaural()       : サウンドモードがモノラルかを問い合わせる。
 *     is_stereo()         : サウンドモードがステレオかを問い合わせる。
 *     is_headphone()      : サウンドモードがヘッドホンかを問い合わせる。
 *     get_svWhiteYsInf()  : 白ヨッシーの情報を得る。
 *     put_svWhiteYsInf(w) : 白ヨッシーの情報(w)を登録する。
 *     get_svBlackYsInf()  : 黒ヨッシーの情報を得る。
 *     put_svBlackYsInf(w) : 黒ヨッシーの情報(w)を登録する。
 *
 *     以下は, 海外対応版のみ有効
 *
 *     set_language(m)     : セーブ情報の国タイプを設定する。
 *                           (m)は SV_JAPAN/SV_USA/SV_FRANCE/SV_GERMANY の
 *                         何れかを設定。
 *     is_JAPAN()          : セーブ情報が日本仕様かを問い合わせる。       
 *     is_USA()            : セーブ情報がアメリカ仕様かを問い合わせる。       
 *     is_FRANCE()         : セーブ情報がフランス仕様かを問い合わせる。        
 *     is_GERMANY()        : セーブ情報がドイツ仕様かを問い合わせる。       
 *
 *  ○ EEPROMセーブのコースクリアーの状態情報操作について
 *
 *     put_clrCourseInf(n)    : ｎコース目のコースクリアー情報を設定する。
 *     get_clrCourseInf(n)    : ｎコース目のコースクリアー情報を得る。
 *     reset_clearCourse(n)   : ｎコース目のコースクリアー情報をリセットする。
 *     resetAll_clearCourse() : 全コースのコースクリアー情報をリセットする。
 *     is_clearCourse(n)      : ｎコース目がコースクリアーか否かの情報を得る。
 *     is_allClearCourse()    : 全てのコースクリアーか否かの情報を得る。
 *
 *  ○ EEPROMセーブのシナリオモードのスコアー情報操作について
 *
 *     put_svScScore(l,s)   : ランキング(l)にスコアー(s)をセーブする。
 *     get_svScScore(l)     : ランキング(l)のスコアーを得る。
 *     clr_svScScore(l)     : ランキング(l)のスコアーをゼロにする。
 *     put_svScName(l,n)    : ランキング(l)に名前(n)を登録する。
 *     get_svScName(l,n)    : ランキング(l)の登録名を(n)に得る。
 *     clrAll_svScLanking() : シナリオモードの全ランキングをクリアーする。
 * 
 *  ○ EEPROMセーブのプリクラモードのスコアー情報操作について
 *
 *     put_svPcScore(c,l,s) : コース(c)のランキング(l)にスコアー(s)をセーブする
 *     get_svPcScore(c,l)   : コース(c)のランキング(l)のスコアーを得る。
 *     clr_svPcScore(c,l)   : コース(c)のランキング(l)のスコアーをゼロにする。
 *     put_svPcName(c,l,n)  : コース(c)のランキング(l)に名前(n)を登録する。
 *     get_svPcName(c,l,n)  : コース(c)のランキング(l)の登録名を(n)に得る。
 *     clrAll_svPcLanking() : プリクラモードの全ランキングをクリアーする。
 *
 *  ○ EEPROMセーブのコンティニュー情報操作について
 *     (この情報の操作は, 海外対応版のみ有効)
 *
 *     put_score(p,s)       : ページ(p)のスコアー(s)をセーブする。 
 *     get_score(p)         : ページ(p)のスコアー(s)を得る。      
 *
 *     is_liveYoshi()       : 生き残りヨッシーがいれば TRUE。
 *     put_[ﾖｯｼｰの色]Ys()   : 指定色のヨッシーに生き残りマークをつける。
 *                            [ﾖｯｼｰの色]は, black/white/yellow/red/pink/green
 *                          /blue/lightblue の何れか選択する。
 *                            <例> put_blackYs();
 *     get_[ﾖｯｼｰの色]Ys()   : 指定色のヨッシーの生き残り情報を得る。
 *     clr_[ﾖｯｼｰの色]Ys()   : 指定色のヨッシーに生き残りマークを消す。
 *     
 *     get_liveWHeiho()     : 白ヘイホー数を得る。  
 *     put_liveWHeiho(n)    : 白ヘイホー数(n)を登録する。   
 *     
 *     get_spHeartNum()     : スペシャルハート数を得る。     
 *     put_spHeartNum(n)    : スペシャルハート数(n)を登録する。     
 *     
 *     get_luckyFruitNum()  : ラッキーフルーツの番号を得る。
 *     put_luckyFruitNum(n) : ラッキーフルーツの番号(n)を登録する。
 *     
 *     clr_lastPage()       : 最後にクリアーしたゲームページ情報を初期化する。
 *     get_lastPage()       : 最後にクリアーしたゲームページを得る。  
 *     put_lastPage(n)      : 最後にクリアーしたゲームページ(n)を登録する。   
 *     get_utuwaHeiho()     :
 *     put_utuwaHeiho(n)    : c
 *     
 *     get_routePage[ﾍﾟｰｼﾞ]()  : ゲームページのゲームクリアーしたルートの情報を
 *                             得る。     
 *                             [ﾍﾟｰｼﾞ]は, 1/2/3/4/5の何れかを選択する。
 *                             <例> get_routePage1();
 *     put_routePage[ﾍﾟｰｼﾞ](n) : ゲームページのゲームクリアーしたルートの情報を
 *                             セーブする。 
 *
 *  ● EEPROMへのアクセスについて
 *    
 *     write_toEEPROM()   : バッファの内容をEEPROMに書き込む。
 *     read_EEPROM()      : バッファの内容をEEPROMから読み込む。
 *     reset_EEPROM()     : EEPROM領域を初期化する。
 *     is_eepromNormal(f) : EEPROMのアクセス結果の 正常/異常 を判定する。正常の
 *                        ときは TRUE になる。
 *                          (f)は write_toEEPROM(), read_EEPROM() の関数。
 *
 *  ◇ セーブ情報のシステム起動時の初期化について
 *
 *     initial_saveInfo() : セーブ情報のシステム起動時の初期化は,この関数で
 *                        行うこと。
 *
 ******************************************************************************
 */
/*
 ******************************************************************************
 *      サウンドのモード設定 (ステレオ/モノラル/ヘッドホン)
 ******************************************************************************
 */
void put_soundMode(int mode)
{
#if SOUND
    static NA_OUT_MODE soundMode[] = {NA_MODE_STEREO,
				      NA_MODE_MONO,
				      NA_MODE_HEADPHONE};

    sNa_OutModeChange(soundMode[mode]);
#endif
    get_option().sound = (t_opsd)mode;
}
/*
 ******************************************************************************
 *      セーブ領域へのランキング者名の 書き込み/読み込み
 ******************************************************************************
 */
#if 0
/* ランキング者名の書き込み */
static void putSvName(char *dName, short *sName, int leng)
{
    int   i;

    for(i=0; i<leng; i++)
	*dName++ = (char)(*sName++ >> BITpBYTE);
}
/* ランキング者名の読み込み */
static void getSvName(short *dName, char *sName, int leng)
{
    int   i;

    for(i=0; i<leng; i++)
	*dName++ = (short)*sName++;
}
#endif

/* ランキング者名の書き込み */
static void putSvName(char *dName, short *sName, int leng)
{
    int   i;

    for (i=0; i<leng; i++) {
	*(dName+i) = (char)((int)(*(sName+i)));
    }
}
/* ランキング者名の読み込み */
static void getSvName(short *dName, char *sName, int leng)
{
    int   i;

    for(i=0; i<leng; i++) {
	*(dName+i) = (short)((int)(*(sName+i)));
    }
}
/*
 ******************************************************************************
 *      シナリオモードのランキング者名の 書き込み/読み込み
 ******************************************************************************
 */
/* ランキング者名の書き込み */
void put_svScName(int lank, short *Name)
{
    putSvName(SCNAMEP_P(get_scnLanking(lank)), Name, SCMD_NM_LENG);
}
/* ランキング者名の読み込み */
void get_svScName(int lank, short *Name)
{
    getSvName(Name, SCNAMEP_P(get_scnLanking(lank)), SCMD_NM_LENG);
}
/*
 ******************************************************************************
 *      プリクラモードのランキング者名の 書き込み/読み込み
 ******************************************************************************
 */
/* ランキング者名の書き込み */
void put_svPcName(int course, int lank, short *Name)
{
    putSvName(getP_pcName(course, lank), Name, PCMD_NM_LENG);
}
/* ランキング者名の読み込み */
void get_svPcName(int course, int lank, short *Name)
{
    getSvName(Name, getP_pcName(course, lank), PCMD_NM_LENG);
}
/*
 ******************************************************************************
 *      指定コース(n)を未クリアーに設定する
 ******************************************************************************
 */
void reset_clearCourse(int n)
{
    if(is_clearCourse(n)) {
	t_cscst  status = get_courseClrStat();

	status &= ALL_COURSE_CLEAR ^ (t_cscst)(0x01 << (n - 1));
	put_courseClrStat(status);
    }
}
#if !JAPAN
/*
 ******************************************************************************
 *      ゲームクリアーしたルート情報の有無を確認する
 *      (ルート情報があれば TRUE を返す)
 ******************************************************************************
 */
int is_routeInfo(void)
{
    return (get_routePage1()
	    || get_routePage2()
	    || get_routePage3()
	    || get_routePage4()
	    || get_routePage5()
	    || get_lastPage());
}
/*
 ******************************************************************************
 *      EEPROMセーブ情報の読み/書き
 ******************************************************************************
 */
/* EEPROMセーブ情報の読み/書きメンバーのテーブル */
typedef struct eeprom_save_member {
        void    *data;		// メンバーへのポインター
        size_t  size;		// メンバーのサイズ
        size_t  eepromSize;     // EEPROM上でのメンバーのサイズ
} EPSVMB;
static EPSVMB eepromSvMemb[] =
{
    {(void *)getP_option(),                      sizeof(OPTINF), 1},
    {(void *)((char *)getP_courseClrStat() + 1), sizeof(CSCLIF), 3},
    {(void *)getP_scnLanking(0),                 sizeof(SCLNIF), 40},
    {(void *)getP_pcLanking(),                   sizeof(PCLNIF), 960},
    {(void *)getP_continueInfo(),                sizeof(CNTNIF), 14},
};

/* EEPROMからセーブ情報を読み込む(失敗すれば TRUE を返す) */
int read_EEPROM(void)
{
    char    saveInfoBuff[SIZE_SAVEINFO];
    char    *saveInfoBuff_p = saveInfoBuff;
    EPSVMB  *eepromSvMemb_p;
    size_t  i;

#if DEBUG
    PRINTF("## EEPROMからセーブ情報を読み込む \n");
#endif
    clr_saveInfo();
    if(!is_eepromNormal(eeprom_load(saveInfoBuff)))
       return TRUE;
    
    for(i=0; i<(sizeof(eepromSvMemb) / sizeof(EPSVMB)); i++) {
	eepromSvMemb_p = &eepromSvMemb[i];
#if 0
	PRINTF("data=%x saveInfoBuff_p=%x size=%d\n",
	       eepromSvMemb_p->data,
	       saveInfoBuff_p,
	       eepromSvMemb_p->eepromSize);
#endif
	cpymem_c(eepromSvMemb_p->data,
		 saveInfoBuff_p,
		 eepromSvMemb_p->eepromSize);
	saveInfoBuff_p += eepromSvMemb_p->eepromSize;
    }
    return FALSE;
}
/* EEPROMへセーブ情報を書き込む */
void write_toEEPROM(void)
{
    char    saveInfoBuff[SIZE_SAVEINFO];
    char    *saveInfoBuff_p = saveInfoBuff;
    EPSVMB  *eepromSvMemb_p;
    size_t  i;
    
#if DEBUG
    PRINTF("## EEPROMへセーブ情報を書き込む \n");
#endif
    for(i=0; i<(sizeof(eepromSvMemb) / sizeof(EPSVMB)); i++) {
	eepromSvMemb_p = &eepromSvMemb[i];
#if 0
	PRINTF("saveInfoBuff_p=%x data=%x size=%d\n",
	       saveInfoBuff_p,
	       eepromSvMemb_p->data,
	       eepromSvMemb_p->eepromSize);
#endif
	cpymem_c(saveInfoBuff_p,
		 eepromSvMemb_p->data,
		 eepromSvMemb_p->eepromSize);
	saveInfoBuff_p += eepromSvMemb_p->eepromSize;
    }
    eeprom_save(saveInfoBuff);
}
#endif
/*
 ******************************************************************************
 *      EEPROMのリセット
 ******************************************************************************
 */
void reset_EEPROM(void) 
{
    eeprom  eepromResetDT = {0};

    eeprom_save((char *)&eepromResetDT);
}
#if EEPROM_TEST
/*
 ******************************************************************************
 *      セーブ情報からEEPROMへのセーブテスト
 ******************************************************************************
 */
void test_eeprom(void)
{
//    short  s_SName[] = {0x01,0x03,0x05,0x07};
//    short  s_PName[] = {0x04,0x06,0x08,0x0A};

    if(!is_eepromNormal(read_EEPROM()))
	reset_EEPROM();

    clr_saveInfo();

    put_clrCourseInf(1);
    put_clrCourseInf(16);
    put_clrCourseInf(23);
    put_soundMode(STEREO);

    PRINTF("## EEPROMテスト 書き込み");
    if(is_eepromNormal(write_toEEPROM()))
	PRINTF(" 正常 !!\n");
    else
	PRINTF(" 異常 !!\n");

    clr_saveInfo();

    PRINTF("## EEPROMテスト 読み込み");
    if(is_eepromNormal(read_EEPROM()))
	PRINTF(" 正常 !!\n");
    else
	PRINTF(" 異常 !!\n");

    PRINTF("## 書き/読み テスト内容 ");
    if(is_stereo()
       && is_clearCourse(1) && is_clearCourse(16) && is_clearCourse(23))
	PRINTF(" 正常 !!\n");
    else
	PRINTF(" 異常 !!\n");
}
#endif
/*
 ******************************************************************************
 *      セーブ情報の初期化
 ******************************************************************************
 */
void initial_saveInfo(void)
{
#if DEBUG
    PRINTF("## セーブ情報のサイズ %d/%d byte \n",
	   sizeof(get_svdataArea()), SIZE_SAVEINFO);
    PRINTF("OPTINF = %d %x \n",
	   sizeof(get_svdataArea().option),
	   &get_svdataArea().option);
    PRINTF("CSCLIF = %d %x \n",
	   sizeof(get_svdataArea().courseClrInfo),
	   &get_svdataArea().courseClrInfo);
    PRINTF("SCLNIF = %d %x \n",
	   sizeof(get_svdataArea().scnLanking),
	   &get_svdataArea().scnLanking);
    PRINTF("PCLNIF = %d %x \n",
	   sizeof(get_svdataArea().pcLanking),
	   &get_svdataArea().pcLanking);
#if !JAPAN
    PRINTF("CNTNIF = %d %x \n",
	   sizeof(get_svdataArea().continueInfo),
	   &get_svdataArea().continueInfo);
#endif
#endif
#if (JAPAN & USE_CHECK_POINT)
    init_svIfLkChk();
#endif
#if !UNUSE_EEPROM
    initial_eeprom();
    if(!is_eepromNormal(read_EEPROM())) {
	clr_saveInfo();
	reset_EEPROM();
    }
#if DEBUG
    if(!is_eepromNormal(read_EEPROM())) {
	PRINTF(__WARNING
	       "EEPROM 異常の可能性がある!! "
	       "EEPROMの初期化, R/Wができない。\n");
    }
#endif
#else
    clr_saveInfo();
#endif // !UNUSE_EEPROM
    put_soundMode((int)get_soundMode());  // サウンドのモード設定

#if (JAPAN & USE_CHECK_POINT)
    /* セーブ情報領域からのデータ漏れのチェックを行う */
    if(is_leakSaveInfo()) {
#if DEBUG
	PRINTF(__ERROR
	       "initial_saveInfo():セーブ情報領域が EEPROM からの読み込み"
	       "データの漏れを起こしている!!\n");
#endif
	__STOP;
    }
#endif
}
