/********************************************************************/
/* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
//////////////////////////////////////////////////////////////////////
// MGOfstream.cpp: MGOfstream クラスのインプリメンテーション
//////////////////////////////////////////////////////////////////////
#include "MGCLStdAfx.h"
#include "mg/Ofstream.h"
#include "mg/Object.h"
#include "mg/Group.h"

#if defined(_DEBUG)
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

using std::ofstream;
using std::ios;

//////////////////////////////////////////////////////////////////////
// Constructor and destructor.
//////////////////////////////////////////////////////////////////////

MGOfstream::MGOfstream()
:m_file(0), m_map(new MGOutPtrMap),m_position(0), m_map_clear(true){}

MGOfstream::MGOfstream(const TCHAR *file, bool map_clear)
:m_file(0),m_map(new MGOutPtrMap),m_position(0){
	open(file,map_clear);
}

MGOfstream::~MGOfstream(){
	close();
	delete m_map;
}

///////////////Operator overload//////////////////

//Write out an object to ofs. Written objects by this function are able
//to read by one of the following global function:
// 1. MGIfstream& operator>>(MGIfstream& file, MGGel*& obj);
// 2. operator>>(MGIfstream& file, MGPvector<MGGel>& vecObj);
// 3. operator>>(MGIfstream& file, MGPlist<MGGel>& listObj);
MGOfstream& MGOfstream::operator<< (const MGGel& obj){
	long tid = obj.identify_type();
	if(tid==MGPLANEIMAGE_TID)
		return *this;
	std::unique_ptr<MGGel> gel(MGNullGel(tid));
	if(gel.get()){
		if(m_map_clear){
			mapClear();
			set_map_clear(false);
		}
		(*this)<<0xffffffffL;//Flag that indicates an object is followed.
		long pid = tellp();  // PIDを決める(streamのPosition)
		insert(&obj,pid);	 //mapに自分自身のPIDを登録

		//データメンバの書き出し
		(*this)<<tid;
		obj.WriteMembers(*this);
	}
	return (*this);
}

void MGOfstream::operator<<(const MGGroup& group){
	int n=group.size();
	(*this)<<n;
	MGGroup::const_iterator i=group.begin(), ie=group.end();
	for(; i!=ie; i++)
		(*this)<<(**i);
}

///////////////Member function//////////////////

void MGOfstream::close(){
	if(m_file) delete m_file;
	m_file=0;
}

//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 MGOfstream::open(const TCHAR* file, bool map_clear){
	m_map_clear=map_clear;
	int error=0;
	std::ofstream* file_new=0;
	file_new = new ofstream(file, ios::out | ios::binary);

	if(file_new && file_new->is_open()){
		if(m_file){
			m_file->close();
			delete m_file;
		}
		m_file=file_new;
		write(MGCL::Version(),8);
		write(MGCL::File_validity(),24);
		error=0;
	}else{
		delete file_new; file_new=0;
		error=1;
	}
	return error;
}

//Write out n bytes date in th buffer ps.
//This read data is row data, and the sequence will not be changed
//like read nByte.
void MGOfstream::write(const void* ps, int n){
	m_file->write((char*)ps,n);
	m_position+=n;
}
