///////////////////////////////////////////////////////////////////////////////
//
// File      : Asura_PS3_SingleStorage.h
// Author    : Philip Hall
// Created   : 07/12/2007
//
// Copyright (C) 2007 Rebellion. All Rights Reserved
//
///////////////////////////////////////////////////////////////////////////////

#if !defined __ASURA_PS3_SINGLESTORAGE_H__
#define __ASURA_PS3_SINGLESTORAGE_H__

// Asura PS3 headers
#include "core/Asura_PS3_Semaphore.h"
#include "fileaccess/Asura_PS3_FileSystem.h"

// platform specific headers
#include <sys/ppu_thread.h>
#include <sysutil/sysutil_savedata.h>

#if !defined ASURA_PS3_MAX_SINGLE_SAVES
	#define ASURA_PS3_MAX_SINGLE_SAVES  4
#endif

////PGH////////////////////////////////////////////////////////////////////////
// How to use 'Asura_PS3_SingleStorage'
//
// Get the product code for your project (see TRCs) 
//
// Construct the appropriate storage object dynamically or statically as you 
// see fit, the completion callback is optional (you can use the wait function).
// e.g
//
//    Asura_PS3_SingleStorage* pxStorage = new Asura_PS3_SingleStorage(ASURA_PS3_PROJECT_PRODUCT_CODE, &Platform_SaveCallback );
//
// If you're saving, set the information about your save file (Title, Subtitle 
// and Param are REQUIRED in most save scenarios)
//
//    pxStorage->SetSaveInfo("Some Title", "Some Subtitle", "", "PARAM");
//
// If you're SAVING:
//
// Add data to the data array for saving. An icon is required if this is not 
// an autosave - setting NULL data parameters will make the routines attempt
// to load data with the same name from the game media.
//
//    pxStorage->AddDataEntry("MISC/ICON0.PNG", NULL, 0, CELL_SAVEDATA_FILETYPE_CONTENT_ICON0 );
//    pxStorage->AddDataEntry("ANYTHING", pAnyData, sizeof(AnyData) );
//    pxStorage->AddDataEntry("SOMETHING", pSomeData, sizeof(SomeData) );
//
// Finally call the save function with a PREFIX code and an optional index - 
// the prefix code and index will result in a save directory with the name 
// "PRODUCTCODE-PREFIX-#" or just "PRODUCTCODE-PREFIX" if no index is specified.
//
//    pxStorage->Save("PREFIX", false, 1);
//
//
// If you're LOADING:
//
// There's no need to retrieve any data you don't need (like the icon) althought
// the current utility libraries don't allow data to be skipped (bizarrely).
//
// Call the load function with a PREFIX code and an optional index - the prefix 
//  code and index will result in a save directory with the name 
// "PRODUCTCODE-PREFIX-#" or just "PRODUCTCODE-PREFIX" if no index is specified.
//
//    pxStorage->Load("PREFIX", false, 2);
//
// To get the data out, you can either poll using the WaitComplete() function 
// or use the callback function - which you can use to copy the data out of 
// the storage object when it's finished loading using GetDataEntry().
//
///////////////////////////////////////////////////////////////////////////////


class Asura_PS3_SingleStorage;

typedef void (*Asura_PS3_StorageCallback)(const Asura_PS3_SingleStorage* pStorage, bool& bDeleteObject);

////PGH/////////////////////////////////////////
// Single directory data storage (not list-based)
////////////////////////////////////////////////
class Asura_PS3_SingleStorage
{
protected:
	static const int ASURA_PS3_MAX_DATA_ENTRIES = 8 + 4;     // 8 entries + 4 for the various icons 'n' bits
	static const int ASURA_PS3_SAVE_NAME_LENGTH = 32;
	struct Asura_PS3_SaveDataEntry
		{
			char   szName[ASURA_PS3_SAVE_NAME_LENGTH];
			void*  pData;
			int    iSize;
			bool   bDeallocate;
			CellSaveDataFileType eType;
		};

public:
	Asura_PS3_SingleStorage(const char* szProductCode, Asura_PS3_StorageCallback pfnCompletion=NULL, void* pUserData=NULL);
	virtual ~Asura_PS3_SingleStorage();
	
	void Destroy();

	virtual bool Load(const char* szPrefix, bool bAutoLoad, int iIndex=-1);
	virtual bool Save(const char* szPrefix, bool bAutoSave, int iIndex=-1);
	bool WaitComplete(int iTimeoutMS);
	
	void  AddDataEntry(const char *szName, void *pData, int iSize, CellSaveDataFileType eType=CELL_SAVEDATA_FILETYPE_SECUREFILE);
	void  ClearDataEntries();
	void* GetDataEntry(const char *szName, int& iSize) const;
	void* GetUserData() const { return m_pUserData; }
	void  SetSaveInfo(const char *szTitle, const char *szSubTitle, const char *szDetail, const char *szParam);
	void  SetParentalLevel(int iLevel) { m_iParentalLevel = iLevel; }
	void  SetOverwrite(bool bOverwrite) { m_bOverwrite = bOverwrite; }

protected:
	virtual void ThreadStorage();
	static  void ThreadStorageProxy(uint64_t uParam);

	static  void LoadStatusCallback( CellSaveDataCBResult* pResult, CellSaveDataStatGet* pGet, CellSaveDataStatSet* pSet );
	static  void LoadFixedCallback( CellSaveDataCBResult* pResult, CellSaveDataListGet* pGet, CellSaveDataFixedSet* pSet );
	static  void LoadFileCallback( CellSaveDataCBResult* pResult, CellSaveDataFileGet* pGet, CellSaveDataFileSet* pSet );
	static  void SaveStatusCallback( CellSaveDataCBResult* pResult, CellSaveDataStatGet* pGet, CellSaveDataStatSet* pSet );
	static  void SaveFixedCallback( CellSaveDataCBResult* pResult, CellSaveDataListGet* pGet, CellSaveDataFixedSet* pSet );
	static  void SaveFileCallback( CellSaveDataCBResult* pResult, CellSaveDataFileGet* pGet, CellSaveDataFileSet* pSet );

protected:
	char                       m_szProductCode[CELL_SAVEDATA_DIRNAME_SIZE];
	char                       m_szDirectory[CELL_SAVEDATA_DIRNAME_SIZE];
	void*                      m_pData;
	u_int                      m_uDataSize;
	bool                       m_bAuto;
	bool                       m_bLoading;
	bool                       m_bOverwrite;
	Asura_PS3_Semaphore        m_xCompleted;
	sys_ppu_thread_t           m_xThreadID;
	void*                      m_pUserData;
	Asura_PS3_StorageCallback  m_pfnCompletionCallback;

	void*                   m_pDataBuffer;
	CellSaveDataNewDataIcon m_xIconData;
	char                    m_szSaveTitle[CELL_SAVEDATA_SYSP_TITLE_SIZE];
	char                    m_szSaveSubTitle[CELL_SAVEDATA_SYSP_SUBTITLE_SIZE];
	char                    m_szSaveDetail[CELL_SAVEDATA_SYSP_DETAIL_SIZE];
	char                    m_szSaveParam[CELL_SAVEDATA_SYSP_LPARAM_SIZE];
	unsigned int            m_iParentalLevel;

	int                     m_iTotalEntries;
	int                     m_iTotalDataSizeKB;
	int                     m_iSaveEntryIndex;
	int                     m_iLoadEntryIndex;
	int                     m_iLoadIndex;
	Asura_PS3_SaveDataEntry m_axFileEntries[ASURA_PS3_MAX_DATA_ENTRIES];
	int                     m_aiLoadMapping[ASURA_PS3_MAX_DATA_ENTRIES];
};



#endif


