/********************************************************************/
/* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
//////////////////////////////////////////////////////////////////////
// MGIfstream.cpp: MGIfstream クラスのインプリメンテーション
//////////////////////////////////////////////////////////////////////

#include "MGCLStdAfx.h"
#include "mg/Tolerance.h"
#include "mg/Ifstream.h"
#include "mg/Gel.h"
#include "mg/Group.h"
#include "mgGL/Context.h"

#if defined(_DEBUG)
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

using std::ifstream;
using std::ios;

//////////////////////////////////////////////////////////////////////
// Constructor and destructor.
//////////////////////////////////////////////////////////////////////

MGIfstream::MGIfstream()
:m_file(NULL), m_map(new MGInPtrMap()),m_position(0),m_map_clear(true){;}

MGIfstream::MGIfstream(const TCHAR *file, bool map_clear)
:m_file(0),m_map(new MGInPtrMap()),m_position(0){
	open(file, map_clear);
}

MGIfstream::~MGIfstream(){
	close();
	delete m_map;
}

///////////////Operator overload//////////////////

//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.
MGIfstream& MGIfstream::operator>>(MGGel*& gel){
	gel=0;
	if(m_map_clear){
		mapClear();
		m_map_clear=false;
	}
	long gelHeader=0;
	(*this)>>gelHeader;
	if(gelHeader != 0xffffffffL) return *this;

	long pid= tellg();
	long TID; (*this) >> TID;
	gel=MGNullGel(TID);
	if(gel){
		insert(pid,gel);	//mapに自分自身のPIDを登録
		gel->ReadMembers(*this);	
	}
	return *this;
}

//Read in all the objects in the file.
//The file should be generated by the following function:
//1. MGOfstream::make_file();
//2. MGOfstream& operator<< (const MGGel& gel);
//3. void operator<<(MGGroup& group);
void MGIfstream::operator>>(MGGroup& group){
	int n;
	(*this)>>n;
	MGGel* gel=0;
	for(int i=0; i<n; i++){
		(*this)>>gel;
		if(!gel)
			return;
		group.push_back(gel);
		//std::cout<<(*gel)<<std::endl;/////:***************
		const MGContext* ctx=dynamic_cast<const MGContext*>(gel);
		if(ctx){
			///<[0]=wc_zero;
			///<[1]=rc_zero;
			///<[2]=mach_zero;
			///<[3]=line_zero;
			///<[4]=angle_zero;
			///<[5]=max_knot_ratio;

			const double* tol=ctx->tolerance();
			MGTolerance::set_wc_zero(tol[0]);
			MGTolerance::set_rc_zero(tol[1]);
			MGTolerance::set_mach_zero(tol[2]);
			MGTolerance::set_line_zero(tol[3]);
			MGTolerance::set_angle_zero(tol[4]);
			MGTolerance::set_max_knot_ratio(tol[5]);
		}
	}
}

///////////////Member function//////////////////

//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 MGIfstream::MGCLHeader(std::ifstream& ar){
	ar.read(m_version,8);
	m_position=8;
	const char* large_version="MGCL0900";
	int comp1=strncmp(large_version, m_version, 4);
	if(comp1!=0)
		return false;
	int comp2=strncmp(large_version+4, m_version+4, 4);
	if(comp2>0)
		return false;

	char fielValid[24];
	ar.read(fielValid,24);
	m_position+=24;
	int comp3=strncmp(MGCL::File_validity(), fielValid, 24);
	if(comp3!=0)
		return false;
	return true;
}

void MGIfstream::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 MGIfstream::open(const TCHAR* file, bool map_clear){
	m_map_clear=map_clear;
	int error=0;
	std::ifstream* file_new=0;
	file_new = new ifstream(file, ios::in | ios::binary);

	if(file_new && file_new->is_open()){
		if(MGCLHeader(*file_new)){
			error=0;
			if(m_file) delete m_file;
			m_file=file_new;
			m_map->pmap.clear();
		}else{
			error=2;
			delete file_new;
		}
	}else{
		delete file_new; file_new=0;
		error=1;
	}
	return error;
}

//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 MGIfstream::read(void* ps, int n){
	m_file->read((char*)ps,n);
	m_position+=n;
}

// Pointer base のオブジェクトファイル入力関数
// 戻り値はオブジェクトポインタ
// Null pointer(0)のときあり。
MGGel* MGIfstream::ReadPointer(){
	long header;
	MGGel* gel;
	(*this)>>header;
	long  pid = tellg();

	if(header==0) return 0;//0 means a null object pointer.
	else if(header!=0xffffffffL){
		//In this case, the header becomes an object pointer.
		gel = find(header);
		assert(gel);//Assert that object found.
		return gel;
	}

	//Read an object.
	long TID; (*this)>>TID;
		//std::cout<<TID<<std::endl;
	gel=MGNullGel(TID);
	if(gel){
		insert(pid,gel);//mapに自分自身のPIDを登録
		gel->ReadMembers(*this);
	}
	return gel;
}