/*
  defines bob_dom_cut - class that can manipulate the CUT1 format and all the 
  underlying objects
*/

#ifndef BOB_DOM_CUT_INCLUDED
#define BOB_DOM_CUT_INCLUDED

#include "bob_dom_base.h"
#include "bob_dom_bob.h"
#include "Settings.h"
#include "bob_dom_frame.h"

#include "../common/ext_utils.h"
#include "../common/strutils.h"

class bob_dom_cut;
class bob_dom_path;
class bob_dom_stat;

class bob_dom_name : public bob_dom_string
{
	public:
		static const hdr_begin=BOB_SECTION_NAME_NAME_BEGIN;
		static const hdr_end=BOB_SECTION_NAME_NAME_END;
		
		bool load(bob_dom_ibinaryfilestream& is) { return bob_dom_string::load(is, hdr_begin, hdr_end); }
		bool toFile(bob_dom_obinaryfilestream& os) { return bob_dom_string::toFile(os, hdr_begin, hdr_end); }
		bool toFile(bob_dom_otextfilestream& os);
};

class bob_dom_constants : public bob_dom_section
{
	public:
		static const hdr_begin=BOB_SECTION_NAME_CONST_BEGIN;
		static const hdr_end=BOB_SECTION_NAME_CONST_END;
		
		struct constant
		{
			int a;
			double b;
			
			constant() { a=0; b=0; }
			bool load(bob_dom_ibinaryfilestream& is);
			
			bool toFile(bob_dom_obinaryfilestream& os);
			bool toFile(bob_dom_otextfilestream& os);
		};
		
		typedef ext::list<constant>::iterator iterator;
		
		ext::list<constant> values;
		
		bool load(bob_dom_ibinaryfilestream& is);
		
		bool toFile(bob_dom_obinaryfilestream& os);
		bool toFile(bob_dom_otextfilestream& os);
};

struct bob_note
{
	int value;
	char *text;
	bob_error_codes errorCode;
	
	bob_note() { value=0; text=0; errorCode=e_noError; }
	~bob_note() { delete[] text; }
	
	bool load(bob_dom_ibinaryfilestream& is);
	bool toFile(bob_dom_obinaryfilestream& os);
	bool toFile(bob_dom_otextfilestream& os);
};

class bob_dom_notes : public bob_dom_section, public bob_dom_cantainer<bob_note>
{
	public:
		static const hdr_begin=BOB_SECTION_NAME_NOTE_BEGIN;
		static const hdr_end=BOB_SECTION_NAME_NOTE_END;
		
		bool load(bob_dom_ibinaryfilestream& is, int lineCount);
		
		bool toFile(bob_dom_obinaryfilestream& os);
		bool toFile(bob_dom_otextfilestream& os);
};

// frame
#ifdef X2BC_USE_INI_FORMATS
class bob_dom_stat : public bob_dom_section, public ext::list<int>
{
	public:
		typedef enum state
		{
			formatted,
			noFormat,
			cannotMatchFormat
		};
		
	private:
		const Settings::StatFormat *m_format;
		state m_state;
		void setstate(state newstate) { m_state=newstate; }
		
	public:
		int frameId;
		
		bob_dom_stat(const Settings *settings) { frameId=0; m_format=0; setstate(formatted); }
		
		state rdstate() const { return m_state; }
		
		bool toFile(bob_dom_obinaryfilestream& os);
		bool toFile(bob_dom_otextfilestream& os, const Settings *settings);
		
		bool load(bob_dom_ibinaryfilestream& is, const Settings *settings);
};
#endif // defined(X2BC_USE_INI_FORMATS)

#ifdef X2BC_USE_INI_FORMATS
	typedef bob_dom_cantainer<bob_dom_stat> FrameContainer;
#else
	typedef bob_dom_cantainer<bob_dom_frame> FrameContainer;
#endif

class bob_dom_path : public bob_dom_section, public FrameContainer
{
	private:
		static const hdr_stat_begin=BOB_SECTION_NAME_STAT_BEGIN;
		static const hdr_stat_end=BOB_SECTION_NAME_STAT_END;
		typedef ext::list<int> TempStatList;
		
		bob_dom_notes m_notes;
		const Settings *m_settings;
		char *m_bodyId;
		
		bool loadStatValues(bob_dom_ibinaryfilestream& is, int count);

	public:
		enum BodyFlags {
			fCamera=1,
			fDirLight=2,
			fOmniLight=10,
			fBody=64,
			fScene=128
		};
		
		static const hdr_begin=BOB_SECTION_NAME_PATH_BEGIN;
		static const hdr_end=BOB_SECTION_NAME_PATH_END;
		
		bob_dom_name name;
		bob_dom_constants constants;
		
		int partIdx;
		int cockpitIdx;
		int parentIdx;
		int bodyFlags; // 'c' for cameras, 'l' for lights
		
		bob_dom_bob *bob;
		
		bob_dom_path(const Settings *s) 
		{ 
			partIdx=0; m_bodyId=0; cockpitIdx=0; bodyFlags=0; parentIdx=null_value; bob=0; 
			m_settings=s;
		}
		
		~bob_dom_path() { delete m_bodyId; delete bob; }
		
		const char * bodyId() const { return m_bodyId; }
		void bodyId(const char *str) { strcreate(m_bodyId, str); }
		
		bob_dom_notes& notes() { return m_notes; }
		
		bool toFile(bob_dom_obinaryfilestream& os, int cutVersion);
		bool toFile(bob_dom_otextfilestream& os, int idx);
		
		bool load(bob_dom_ibinaryfilestream& is, int version);
		
		//bool formatStats();
		
		child_type* createChild() 
		{ 
			child_type *ch; 
#ifdef X2BC_USE_INI_FORMATS
			ch=new bob_dom_stat(m_settings);
#else
			ch=new bob_dom_frame();
#endif
			children.push_back(ch); return ch; 
		}
};

class bob_dom_cut : public bob_dom_section, public bob_dom_cantainer<bob_dom_path>
{
	private:
		int m_storedPathCount;
		const Settings *m_settings;

	public:
		static const hdr_begin=BOB_SECTION_NAME_CUT_BEGIN;
		static const hdr_end=BOB_SECTION_NAME_CUT_END;
		
		static const int supported_version = 6;
		
		int version;
		bob_dom_info info;
		
		bob_dom_cut(const Settings *s) { m_settings=s; version=0; m_storedPathCount=0; }
		
		bool toFile(bob_dom_obinaryfilestream& os);
		bool toFile(bob_dom_otextfilestream& os);
		
		value_type_ptr createChild() { return *(children.push_back(new bob_dom_path(m_settings))); }
		
		
		bool load(bob_dom_ibinaryfilestream& is);
		
		bool convert(bob_dom_ibinaryfilestream& is, bob_dom_otextfilestream& os);
		
		//bool formatStats();
};


template <class Ty>
inline
Ty& operator << (Ty& os, bob_dom_info& info)
{
	info.toFile(os);
	return os;
}

template <class Ty>
inline
Ty& operator << (Ty& os, bob_dom_name& right)
{
	right.toFile(os);
	return os;
}

template <class Ty>
inline
Ty& operator << (Ty& os, bob_dom_path& right)
{
	right.toFile(os);
	return os;
}

#ifdef X2BC_USE_INI_FORMATS
template <class Ty>
inline
Ty& operator << (Ty& os, bob_dom_stat& right)
{
	right.toFile(os);
	return os;
}
#endif

#endif // !defined(BOB_DOM_CUT_INCLUDED)