/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
#ifndef _MGIfstream_HH_
#define _MGIfstream_HH_

#include <stdio.h>
#include <fstream>
#include <map>
#include "mg/Object.h"

//forward declerations
class MGGel;
class MGPCell;
class MGBCell;
class MGGroup;
class MGInPtrMap;

/** @addtogroup FileInputOutput
 *  @{
 */

///MGIfstream is a class to read the serialized data generated by MGOfstream.

///All of the MGGel data serialized can be read by :
///(1) Construct: MGIfstream strm(file_name).
///(2) Then, MGGroup grp; strm>>grp.
///(3) The above grp holds all of the serialized data.
class MG_DLL_DECLR MGIfstream{

	typedef std::map<long, MGGel*>::iterator mapitr;
	typedef std::map<MGBCell*, SharedBCell*>::iterator sharedBCellMapItr ;
private:
	/// Object's pointer map.
	std::map<long, MGGel*> m_mapPidGel;
	std::map<MGBCell*, SharedBCell*> m_SharedBCellMap;

	///Input buffer's current position in MGIfstream by byte.
	int m_position;

	///Version number of reading stream.
	char m_version[8];

public:

/// Target input data stream. m_file is a public member.
/// All of the CFile's member functions can be used.
std::ifstream* m_file;
////////////////////////////////////////////////////

///Default constructor.
MGIfstream();

///Ordinal constructor, file name file is used to open the file.
MGIfstream(const TCHAR* file);

///Destructor.
virtual ~MGIfstream();

////////////operator overloaded///////////////

///Read in an object into gel. Returned gel is:
///(1) null if end of file or illegal file.
///(2) non null newed object pointer. User must delete it.
///If you know gel's concrete class, use its function ReadMembers()(which
///is written out by WriteMembers()).
MGIfstream& operator>>(MGGel*& gel);

/// 基本型のファイル入力関数
MGIfstream& operator >>(char& ch){ read1Byte(&ch); return *this; };
MGIfstream& operator >>(unsigned char& uch){ read1Byte(&uch); return *this; };
MGIfstream& operator >>(short& s){ read2Byte(&s); return *this; };
MGIfstream& operator >>(unsigned short& us){ read2Byte(&us); return *this; };
MGIfstream& operator >>(int& n){ read4Byte(&n); return *this; };
MGIfstream& operator >>(unsigned int& un){ read4Byte(&un); return *this; };
MGIfstream& operator >>(long& l){ read4Byte(&l); return *this; };
MGIfstream& operator >>(unsigned long& ul){ read4Byte(&ul); return *this; };
MGIfstream& operator >>(float& f){ read4Byte(&f); return *this; };
MGIfstream& operator >>(double& d){ read8Byte(&d); return *this; };

/////////Member functions//////////

///Close the file. This can be used even open() was not used.
///Users need not use this close() if need not specify the file close
///before the destruction of the MGIfstream.
void close();

///Clear the map area m_mapPidGel&m_SharedBCellMap.
void mapClear();


///Find the input pid's map address.
///If found, MGGel* will be returned.
///If not found, null pointer(0) will be returned.
MGGel* findGel(long pid);

///Insert the ptr into the map.
///Function's return value is:
///True: if ptr did not exist in the map and insertion succeeded.
///False: if ptr did exist in the map and insertion failed.
bool insert(long pid, MGGel* ptr);

void insertSharedBCell(SharedBCell* sbcel);
SharedBCell* findSharedBCell(MGBCell* bcel);

/// fileのオープン.
///Open the file. This is useful when default constructor MGOfstream() is used, or
///to reopen other files.
///Function's return value is:
///=0: open succeeded.
///=1: file not found, or could not be opened.
///=2: file found, but, the format is not MGCL format.
int open(const TCHAR* file);

/// Pointer base のオブジェクトファイル入力関数.
/// 戻り値はオブジェクトポインタ.
/// Null pointer(0)のときあり。
MGGel* ReadPointer();

///n char版.
MGIfstream& readnChar(char* ps4, int n);

/// 出力ポインタ位置関数.
///Tell the current input position of m_file(same as m_file.tellg).
long tellg();

///Obtain the version number of the stream.
const char* version()const{return m_version;};
char* version(){return m_version;};

private:

void clearSharedBCellMap(){ m_SharedBCellMap.clear(); };

///Check if this is the right MGCL file.
///Function's return value is:
///true: if this is the right MGCL file.
///false: if this is not the right MGCL file.
bool MGCLHeader(std::ifstream&);

///Read in n bytes date in th buffer ps.
///This read data is row data, and the sequence will not be changed
///like read nByte.
void read(void* ps, int n);

///1Byte版.
MGIfstream& read1Byte(void* ps2);

///2Byte版.
MGIfstream& read2Byte(void* ps2);

///4Byte版.
MGIfstream& read4Byte(void* ps4);

///8Byte版.
MGIfstream& read8Byte(void* ps4);


friend class MGGroup;
};

/** @} */ // end of FileInputOutput group

#endif	//#ifndef _MGIfstream_HH_
