//==================================================================================================
//	簡易物件資料庫快取物件
//
//
//==================================================================================================
#ifndef	_OBJECTDATABASEFILE_HEADER_
#define	_OBJECTDATABASEFILE_HEADER_

#pragma warning (disable:4949)
#pragma	warning (disable:4786)
#pragma unmanaged

#include    <map>
#include    <vector>
#include	<stdio.h>
#include    <algorithm>

#include    "BaseFunction/BaseFunction.h"
#include    "SmallObj/SmallObj.h"
#include    "ReaderClass/ReaderClass.h"
#include    "Malloc/MyAlloc.h"
//-------------------------------------------------------------------------------
//基本要使用此物件的結構
/*
struct BaseObjStruct
{
    int     GUID;
    int     Class();
};
*/
//-------------------------------------------------------------------------------
#define     DEF_ITEMOBJ_FILE_ID     0x6396

using namespace std;
//-------------------------------------------------------------------------------
struct ObjFileHead
{   
    char    FileInfoStr[ 16 ];  //檔案資訊
    long    Idenitfy;           //識別字
    long    Count;
    long    Size;

    ObjFileHead( )
    {
        Idenitfy = DEF_ITEMOBJ_FILE_ID;
        strcpy( FileInfoStr , "Item Obj File" );
    };
};
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------

template <class T>
class	ObjectDataFileClass
{
    
private:
	map < int , T* >	_ObjData;
	vector< char* >	    _SourceData;
	char*			    _DataBeginAddr;

public:
    //-----------------------------------------------------------
    //
    //-----------------------------------------------------------
    static bool ObjCmp (T* A, T* B) 
    {
        return A->GUID < B->GUID;
    };
    //-----------------------------------------------------------

	ObjectDataFileClass();
	~ObjectDataFileClass();
	
	void	Release();                                  //資料釋放
	bool	OpenFile( const char *FileName);                   //讀檔   
    bool	SaveFile( const char *FileName );                 //檔案一比結構的大小

    bool	OpenTxtFile(char *FileName , ReaderClass<T> *Reader );    //讀檔
    //bool	SaveTxtFile( char *FileName );              //檔案一比結構的大小


	//取得GUID = id 的物件
	//T*		GetObject( int id );
    //T*		GetObj( int id ){ return GetObject(id);};
	T*		GetObj( int id );

	//取得目前有幾筆資料
	int		TotalInfoCount( )			{return (int)_ObjData.size();};

	//循序取資料
    //IsResetData = false   取資料
    //IsResetData = true    重設循序取資料資訊(return true;)
	T*		GetDataByOrder( bool IsResetData = false );

	//把某一個資料設定到此物件
	void	SetData( T* );
};
//-------------------------------------------------------------------------------------------------
//資料釋放
template <class T>
void	ObjectDataFileClass<T>::Release()
{
	int i;
	for( i = 0 ; i < (int)_SourceData.size() ; i++ )
	{
		delete _SourceData[i];
	}

	_SourceData.clear();
}

//-------------------------------------------------------------------------------------------------
template <class T>
ObjectDataFileClass<T>::ObjectDataFileClass()
{
};//ObjectDataFileClass::ObjectDataFileClass
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
template <class T>
ObjectDataFileClass<T>::~ObjectDataFileClass()
{
	Release();
};//ObjectDataFileClass::~ObjectDataFileClass
//-------------------------------------------------------------------------------------------------
//	開啟檔案
//-------------------------------------------------------------------------------------------------
template <class T> 
bool ObjectDataFileClass<T>::OpenFile( const char *FileName)
{
    ObjFileHead       Head;
    FileStreamPtr<>   File;
    T*                Data;
    int               i;

    
    if( ruSEC_OK != File->Open( FileName ) )
        return false;

    File->Read( &Head , sizeof(Head) );

    if( Head.Idenitfy != DEF_ITEMOBJ_FILE_ID )
        return false;
    
    if( (unsigned)Head.Size > sizeof( T ) )
        return false;

    Data = NEW (T [ Head.Count  ]);
    _SourceData.push_back( (char*)Data );

    for( i = 0 ; i < Head.Count ; i++ )
    {
        T* D1 = &Data[ i ];
        File->Read( D1 , Head.Size );
        _ObjData[D1->GUID ] = D1;
    }

    return true;
};//OBJECTDATABASEFILE::OpenFile
//-------------------------------------------------------------------------------------------------
//	存檔
//-------------------------------------------------------------------------------------------------
template <class T> 
bool ObjectDataFileClass<T>::SaveFile( const  char *FileName)
{
    ObjFileHead      Head;
    FileStreamPtr<>  File;
    T*               Data;
    int              i;


    if( ruSEC_OK != File->Create( FileName ) )
        return false;

    Head.Count = (int)_ObjData.size();
    Head.Size  = sizeof(T);

    File->Write( &Head , sizeof(Head) );

    map <int,T*>::iterator	 Iter;
    vector<T*>               SaveData;

    Iter = _ObjData.begin();
    for( i = 0 ; i < Head.Count ; i++ , Iter++ )
    {
        SaveData.push_back( Iter->second );
    }
    
    sort( SaveData.begin() , SaveData.end() , ObjCmp );

    for( i = 0 ; i < (int)SaveData.size() ; i++ )
    {
        Data = SaveData[ i ];
        File->Write( Data , sizeof( T ) );
    }

    return true;
}
//-------------------------------------------------------------------------------------------------
template <class T> 
bool	ObjectDataFileClass<T>::OpenTxtFile( char *FileName , ReaderClass<T> *Reader )
{
//    ReaderClass<T> *Reader;
//    Reader = T::GetReader( Type );

    char	seps[] = " \t\n\r";
    vector< string >            _NameList;
    vector< ReadInfoTypeENUM >  _TypeList;
    char    Buf[ 0x10000 ];
    int     ArgCount;
    int     i;
    T       Data;  

    FILE*	file;
    if (NULL == (file = fopen(FileName, "rb")))
        return false;

    //----------------------------------------------------------
    //取得名稱列表
    if( NULL == fgets( Buf , sizeof( Buf ) , file ) )
        return false;
    
    char* token = strtok( Buf , seps );
    for( ArgCount = 0 ; token != NULL ; ArgCount++ )
    {
        _strlwr( token );
        _NameList.push_back( token );
        token = strtok( NULL , seps );
    }
    //----------------------------------------------------------
    //取得Type列表
    if( NULL == fgets( Buf , sizeof( Buf ) , file ) )
        return false;

    token = strtok( Buf , seps );
    for( i = 0 ; i < ArgCount ; i++ )
    {
        if( token == NULL )
        {
            TRACE1( "ObjectDataFileClass<T>::OpenTxtFile Read Type Count Error!! FileName = %s " , FileName );
            return false;
        }

        _strlwr( token );
        if( strcmp( token , "str" ) == 0 )
        {
            _TypeList.push_back( EM_Type_CharString  );
        }
        else if( strcmp( token , "int" ) == 0 )
        {
            _TypeList.push_back( EM_Type_Int );
        }
        else
        {
            TRACE1( "ObjectDataFileClass<T>::OpenTxtFile Read Type Error!! FileName = %s " , FileName );
            return false;
        }
        token = strtok( NULL , seps );
    }
    int Line = 2;
    //----------------------------------------------------------
    while( NULL != fgets( Buf , sizeof( Buf ) , file ) )
    {
        Line ++;
       
        char* token = strtok( Buf , seps );
        for( i = 0 ; i < ArgCount ; i++ )
        {
            if( token == NULL )
            {
                TRACE2( "File Line = %d : Read Value Error!! FileName = %s " , Line , FileName );
                break;
            }
            switch( _TypeList[ i ] )
            {
            case EM_Type_CharString:
                Reader->WriteStr( &Data , _NameList[ i ].c_str() , token  );
                break;
            case EM_Type_Int:
                Reader->Write( &Data , _NameList[ i ].c_str() , atol( token ) );
                break;

            }
            token = strtok( NULL , seps );
        }

        SetData( &Data );
    }
    //----------------------------------------------------------

    return true;
}
/*
template <class T> 
bool	ObjectDataFileClass<T>::SaveTxtFile( char *FileName )
{
    return false;
}*/
//-------------------------------------------------------------------------------------------------
//	取得物件(經由快取)
//-------------------------------------------------------------------------------------------------
template <class T> 
T*	ObjectDataFileClass<T>::GetObj(int	id)
{
    if( id == 0 )
        return NULL;

	std::map <int,T*>::iterator Iter;
	Iter = _ObjData.find( id );
	if( Iter == _ObjData.end() )
		return NULL;

	return Iter->second;

};//OBJECTDATABASEFILE::GetObject
//-------------------------------------------------------------------------------------------------
//	版本取得
//-------------------------------------------------------------------------------------------------
//循序取資料
template <class T> 
T* ObjectDataFileClass<T>::GetDataByOrder( bool IsResetData )
{
    static std::map <int,T*>::iterator Iter;

    if( IsResetData == true )
    {
        Iter = _ObjData.begin();
        return NULL;
    }

	std::map <int,T*>::iterator	 TempIter;

	if( Iter == _ObjData.end() )
		return NULL;

	TempIter = Iter ++;

	if( TempIter == _ObjData.end() )
		return NULL;

	return TempIter->second;
}
//-------------------------------------------------------------------------------------------------
//把某一個資料設定到此物件
//-------------------------------------------------------------------------------------------------
template <class T> 
void	ObjectDataFileClass<T>::SetData( T* Data )
{
    T* NewData = NEW ( T );
    memcpy( NewData , Data , sizeof(T) );

    _SourceData.push_back( (char*)NewData );
    
	_ObjData[Data->GUID ] = NewData;
}
//-------------------------------------------------------------------------------------------------
#pragma managed
#endif

