#include "bob_dom.h"

#include "../common/indian.h"

#include <stdio.h>

//---------------------------------------------------------------------------------
static char * bob_errors[]= {
	"No error.",
	"Bad header.",
	"Bad ending header.",
	"Not enough data.",
	"More data than expected.",
	"Unknown Point header (tag).",
	"General error.",
	"No STAT format available.",
	"Not enough data to match STAT format.",
	"Format marked with warning sign was used.",
	"Point not found in section POIN.",
	"Invalid version",
	"Unsupported bits set in frame flags",
	"Unknown material6 value type"
	
	// don forget to increase bob_error_count below!
};

#define bob_error_count 14

const char* bob_traslate_error(bob_error_codes code)
{
	if(code >= 0 && code < bob_error_count)
		return bob_errors[code];
	else
		return bob_errors[e_error];
}
//---------------------------------------------------------------------------------
// STRING - object
bool bob_dom_string::load(bob_dom_ibinaryfilestream& is, int startHeader, int endHeader)
{
	int hdr;
	is >> hdr;
	if(hdr!=startHeader){
		error(e_badHeader);
		return false;
	}
	delete m_text;
	is >> m_text;
	if(m_text==0){
		error(e_notEnoughData);
		return false;
	}
	is >> hdr;
	if(hdr!=endHeader)
		error(e_badEndHeader);
	return hdr==endHeader;
}
//---------------------------------------------------------------------------------
bool bob_dom_string::toFile(bob_dom_obinaryfilestream& os, int begin, int end)
{
	if(m_text && *m_text!=0)
		os << begin << m_text << end;
		
	return os.good();
}
//---------------------------------------------------------------------------------
// INFO
bool bob_dom_info::toFile(bob_dom_otextfilestream& os)
{
	if(m_text && *m_text!=0)
		os << noSemicolons << "/# " << m_text << endl;
	return os.good();
}
//---------------------------------------------------------------------------------
// BOB_WITH_ERRORS - object
void bob_with_errors::verror(bob_error_severity severity, bob_error_codes code, const char *format, va_list ap)
{
	bob_error *e=new bob_error();
	_vsnprintf(e->text, sizeof(e->text), format, ap);
	e->code=code;
	e->severity=severity;
	errors.push_back(e);
}
//---------------------------------------------------------------------------------
void bob_with_errors::error(bob_error_severity severity, bob_error_codes code)
{
	error(severity, code, "%s", bob_traslate_error(code));
}
//---------------------------------------------------------------------------------
void bob_with_errors::error(bob_error_codes code)
{
	error(s_error, code);
}
//---------------------------------------------------------------------------------
void bob_with_errors::error(bob_error_severity severity, bob_error_codes code, const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	verror(severity, code, format, ap);
	va_end(ap);
}
//---------------------------------------------------------------------------------
void bob_with_errors::error(bob_error_codes code, const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	verror(s_error, code, format, ap);
	va_end(ap);
}
//---------------------------------------------------------------------------------
int peek(bob_dom_ibinaryfilestream& is)
{
	int i;
	is >> i;
	is.advance(-(int)sizeof(int));
	return i;
}
//---------------------------------------------------------------------------------
// DOCUMENT
bool bob_dom_document::fromFile(bob_dom_ibinaryfilestream& is)
{
	bool bRes=false;
	bob_with_errors *e=0;
	char *name="";

	clearErrors();
	
	switch(peek(is)){
		case bob_dom_bob::hdr_begin:
			bob=new bob_dom_bob(settings);
			e=bob;
			name="bob";
			bRes=bob->load(is);
			break;
		case bob_dom_cut::hdr_begin:
			cut=new bob_dom_cut(settings);
			e=cut;
			name="cut";
			bRes=cut->load(is);
			break;
		default:
			error(F_BOBLoader, S_Error, E_BadHeader, "Bad document header.");
	}

	if(e){
		for(bob_with_errors::ErrorIterator &it=e->errors.begin(); it!=e->errors.end(); ++it){
			bob_error(it->severity, it->code, "%s->%s", name, it->text);
		}
	}
	return bRes;
}
//---------------------------------------------------------------------------------
#include <time.h>
bool bob_dom_document::convert(bob_dom_ibinaryfilestream& is, bob_dom_otextfilestream& os)
{
	bool bRes=false;
	bob_with_errors *e=0;
	char *pszTime;
	char *name="";
	
	time_t tm=time(0);
	pszTime=ctime(&tm);
	pszTime[strlen(pszTime)-1]=0;
	
	clearErrors();
	
	os << "// Converted with x2bc from \"" << is.name() << "\" at " << pszTime << endl;
	if(settings->convert()==false)
		os << "// Raw mode - values are not converted" << endl;
	os << endl;
	
	switch(peek(is)){
		case bob_dom_bob::hdr_begin:
			bob=new bob_dom_bob(settings);
			e=bob;
			name="bob";
			bRes=bob->load(is);
			if(bRes) bRes=bob->toFile(os);
			break;
		case bob_dom_cut::hdr_begin:
			cut=new bob_dom_cut(settings);
			e=cut;
			name="cut";
			bRes=cut->convert(is, os);
			break;
		default:
			error(F_BOBLoader, S_Error, E_BadHeader, "Bad document header.");
	}

	if(e){
		for(bob_with_errors::ErrorIterator &it=e->errors.begin(); it!=e->errors.end(); ++it){
			bob_error(it->severity, it->code, "%s->%s", name, it->text);
		}
	}
	return bRes;
}
//---------------------------------------------------------------------------------
bool bob_dom_document::toFile(bob_dom_obinaryfilestream& os)
{
	if(bob)
		bob->toFile(os);
		
	else if(cut)
		cut->toFile(os);
		
	return os.good();
}
//---------------------------------------------------------------------------------
bool bob_dom_document::toFile(bob_dom_otextfilestream& os)
{
	os << noSemicolons << "// Converted with x2bc" << endl;
	if(settings->convert()==false)
		os << "// Raw mode - values are not converted" << endl;
	os << endl;
	
	if(bob)
		bob->toFile(os);
		
	else if(cut)
		cut->toFile(os);
		
	return os.good();
}
//---------------------------------------------------------------------------------
void bob_dom_document::error(ErrorFacility facility, ErrorSeverity severity, ErrorCode code, const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	verror(facility, severity, code, format, ap);
	va_end(ap);
}
//---------------------------------------------------------------------------------
void bob_dom_document::verror(ErrorFacility facility, ErrorSeverity severity, ErrorCode code, const char *format, va_list ap)
{
	Error *e=new Error();
	
	e->makeCode(facility, severity, code);
	_vsnprintf(e->text, sizeof(e->text), format, ap);
	errors.push_back(e);
}
//---------------------------------------------------------------------------------
void bob_dom_document::bob_error(bob_error_severity severity, bob_error_codes code, const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	vbob_error(severity, code, format, ap);
	va_end(ap);
}
//---------------------------------------------------------------------------------
void bob_dom_document::vbob_error(bob_error_severity severity, bob_error_codes code, const char *format, va_list ap)
{
	ErrorCode c;
	ErrorSeverity s;
	ErrorFacility f=F_BOBLoader;
	switch(code) {
		case e_badEndHeader:
			c=E_BadEndHeader;
			break;
		case e_badHeader:
			c=E_BadHeader;
			break;
		case e_moreData:
			c=E_MoreData;
			break;
		case e_noError:
			c=E_NoError;
			s=S_OK;
			break;
		case e_format_noStatFormat:
			c=E_NoStatFormat;
			f=F_StatLoader;
			break;
		case e_format_notEnoughData:
			c=E_NotEnoughData;
			f=F_StatLoader;
			break;
		case e_format_UserWarning:
			c=E_FormatUserWarning;
			s=S_Warning;
			f=F_StatLoader;
			break;
		case e_notEnoughData:
			c=E_NotEnoughData;
			break;
		case e_unkPointHeader:
			c=E_UnkPointHeader;
			break;
		case e_pointNotFound:
			c=E_PointNotFound;
			break;
		case e_badVersion:
			c=E_BadVersion;
			break;
		case e_error: // nobreak
		default:
			c=E_Error;
	}
	s=(severity==s_warning ? S_Warning : S_Error);
	verror(f, s, c, format, ap);
}
//---------------------------------------------------------------------------------
