/**
@file xml_save.hpp
@note
it was based on boost/archive/detail/basic_xml_oarchive.ipp:
convert xml_save.hpp by d.Kingyo http://dkingyoutility.sourceforge.jp

basic_xml_oarchive.ipp:
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org for updates, documentation, and revision history.


*/
#ifndef DKUTIL_PARSER_XML_SAVE_HPP
#define DKUTIL_PARSER_XML_SAVE_HPP

#include <dkutil/macro.hpp>
#include <dkutil/parser/string_util.hpp>
#include <dkutil/detail/stream_interface.hpp>
namespace dkutil{

#define DKUTIL_XML_SAVE_DEFAULT_DOCTYPE "dkutil_filesystem_xml_save"

#define DKUTIL_XML_SAVE_DEFAULT_HEADER_SIG "dkutil_filesystem_xml_save_sig"

class xml_save{
	IStream *mp;
	int depth;
	bool indent_next;
	bool pending_preamble;
	bool header;
	bool inited;
	std::string mDocType;
	std::string mHeaderSig;
	void inner_init(IStream *p){
		mp = p;
		depth = 0;
		indent_next = false;
    pending_preamble = false;
    header = false;
		inited = false;
		set_sig();
	}
	void init(){
		// xml header
		header = true;
		write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n");
		write("<!DOCTYPE ");
		write(mDocType.c_str());
		write(">\n");
		// xml document wrapper - outer root
		write("<");
		write(mHeaderSig.c_str());
		write_attribute("signature", ARCHIVE_SIGNATURE); 
		write_attribute_uint32("version", ARCHIVE_VERSION); 
		write(">\n");
	}
	void set_sig(){
		ARCHIVE_SIGNATURE = "dkutil::xml_save";
		ARCHIVE_VERSION = 1;
		OBJECT_ID = "object_id";
		OBJECT_REFERENCE = "object_id_reference";
		CLASS_ID = "class_id";
		CLASS_ID_REFERENCE = "class_id_reference";
		CLASS_NAME = "class_name";
		TRACKING = "tracking_level";
		VERSION = "version";
		SIGNATURE = "signature";
		DEFAULT_DOCTYPE = DKUTIL_XML_SAVE_DEFAULT_DOCTYPE;
		DEFAULT_HEADER_SIG = DKUTIL_XML_SAVE_DEFAULT_HEADER_SIG;
	}
public:
	const char *ARCHIVE_SIGNATURE;
	unsigned int ARCHIVE_VERSION;
	const char *OBJECT_ID;
	const char *OBJECT_REFERENCE;
	const char *CLASS_ID;
	const char *CLASS_ID_REFERENCE;
	const char *CLASS_NAME;
	const char *TRACKING;
	const char *VERSION;
	const char *SIGNATURE;
	const char *DEFAULT_DOCTYPE;
	const char *DEFAULT_HEADER_SIG;

	bool good()const{
		return NULL != mp;
	}
	
	xml_save(IStream *pAtatch)
	{
		inner_init(pAtatch);
		reset(pAtatch);
	}
	xml_save(){
		inner_init(NULL);
	}
	~xml_save(){
		clear();
	}
	void set_doctype(parm_string str){
		if(str.size() == 0){
			mDocType = DEFAULT_DOCTYPE;
		}else{
			mDocType = str.c_str();
		}	
	}
	void set_header_sig(parm_string header_sig){
		if(header_sig.size() == 0){
			mHeaderSig = DEFAULT_HEADER_SIG;
		}else{
			mHeaderSig = header_sig.c_str();
		}	

	}
	
	void clear(){
		if(!header)
					return;
		write("</");
		write(mHeaderSig.c_str());
		write(">\n");
		mDocType.clear();
		mHeaderSig.clear();
		inited = false;
	}

	bool reset(IStream *p,
		parm_string header_sig = DKUTIL_XML_SAVE_DEFAULT_HEADER_SIG,
		parm_string doct = DKUTIL_XML_SAVE_DEFAULT_DOCTYPE)
	{
		clear();
		inner_init(p);
		set_doctype(doct);
		set_header_sig(header_sig);
		init();
		if(NULL==p) return false;

		
		inited = true;
		return true;
	}
	void write(parm_string s){
		if(good())
			mp->write(s.c_str(),s.size());
		else{
			DKUTIL_THROW_OR_NOTICE(std::runtime_error("xml_save stream object pointer null"));
		}
	}
	void write(char s){
		
		mp->write(&s,1);
		
	}
	void write_attribute_uint32(
	  const char *attribute_name, 
	  uint32 t,
	  const char *conjunction = "=\""
	){
		  write(" ");
		  write(attribute_name);
		  write(conjunction);
		  write(to_string_uint32((uint32)t));
		  write("\"");
	}
	void write_attribute_uint64(
		const char *attribute_name, 
	  uint64 t,
	  const char *conjunction = "=\""
	){
		  write(" ");
		  write(attribute_name);
		  write(conjunction);
		  write(to_string_uint64(t));
		  write("\"");
	}
	void write_attribute(
		  const char *attribute_name, 
		  const char *key
	){
		  write(" ");
		  write(attribute_name);
		  write("=\"");
		  write(key);
		  write("\"");
	}
	
	void indent(){
		int i;
		for(i = depth; i-- > 0;)
			write('\t');
	}


	void save_start(const char *name)
	{
		if(false==inited)
			DKUTIL_THROW_OR_NOTICE(std::runtime_error("xml_save not initialize"));
		if(NULL == name)
				return;
		end_preamble();
		if(depth > 0){
			write('\n');
			indent();
		}
		++depth;
		write('<');
		write(name);
		pending_preamble = true;
		indent_next = false;
	}


	void save_end(const char *name)
	{
		if(false==inited)
			DKUTIL_THROW_OR_NOTICE(std::runtime_error("xml_save not initialize"));
		if(NULL == name)
				return;
		end_preamble();
		--depth;
		if(indent_next){
				write('\n');
				indent();
		}
		indent_next = true;
		write("</");
		write(name);
		write('>');
		if(0 == depth)
				write('\n');
	}


	void end_preamble(){
		if(pending_preamble){
				write('>');
				pending_preamble = false;
		}
	}


	/*
	void save_override(const object_id_type & t, int)
	{
		int i = t.t; // extra .t is for borland
		write_attribute(OBJECT_ID, i, "=\"_"); 
	}

	void save_override(
			const object_reference_type & t,
			int
	){
		int i = t.t; // extra .t is for borland
		write_attribute(OBJECT_REFERENCE, i, "=\"_"); 
	}

	void save_override(const version_type & t, int)
	{
		int i = t.t; // extra .t is for borland
		write_attribute(VERSION, i); 
	}

	void save_override(const class_id_type & t, int)
	{
		write_attribute(CLASS_ID, t); 
	}

	void save_override(
			const class_id_reference_type & t,
			int
	){
		write_attribute(CLASS_ID_REFERENCE, t); 
	}

	void save_override(
			const class_id_optional_type & t,
			int
	){
		write_attribute(CLASS_ID, t); 
	}

	void save_override(const class_name_type & t, int)
	{
		const char * key = t;
		if(NULL == key)
				return;
		write_attribute(CLASS_NAME, key); 
	}

	void save_override(const tracking_type & t, int)
	{
			write_attribute(TRACKING, t.t); // extra .t is for borland 
	}
	*/







};















}//end of dkutil namespace




#endif//end of include once
