#include"CXMLWriter.h"
#include"../CString.h"
#include"../Debug/CAssert.h"
#include"../FileIO/CFileWrite.h"

#include<stdio.h>

/*
	{
		CXMLWriter write;

		write.AscendNode(L"top");
			write.SetElementName( L"child1" );
			write.SetValueText( L"value" );

			write.NextNode();

			write.AscendNode(L"tag");
				write.SetElementName( L"child3" );
				write.SetValueInt( 100 );

				write.DescendNode();

			write.NextNode();
			write.SetElementName( L"child2" );
			write.SetValueFloat( 0.5f );

		write.DescendNode();

		write.Save( L"hoge.xml" );
	}

	↑のコードで↓みたいになる

<?xml version="1.0" encoding="shift_jis" ?> 
<top>
	<child1>value</child1> 
	<tag>
		<child3>100</child3> 
	</tag>
	<child2>0.500000</child2> 
</top>
*/


namespace Maid
{
	CXMLWriter::CXMLWriter()
	{
		m_pCurrentNode.reset( new CXMLNode );
	}

	/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
	//! ひとつ入る
	/*!
	*/
	void CXMLWriter::AscendNode( const mstring& ElementName )
	{
		SetElementName(ElementName);

		SPXMLNODE pNew( new CXMLNode );
		m_pCurrentNode->AddChildNode( pNew );

		m_ParentStack.push( m_pCurrentNode );

		m_pCurrentNode = pNew;
	}

	/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
	//! ひとつ出る
	/*!
	*/
	void CXMLWriter::DescendNode()
	{
		MAID_ASSERT( m_ParentStack.empty(), "これ以上昇れません" );

		//	要素名を設定してないときにassertを出したいんだけど
		//	AscendNode()直後のDescendNode()に対応できないので
		//	チェックしない
		//	MAID_ASSERT( m_pCurrentNode->GetElementName().empty(), "要素名を決める必要があります" );

		m_pCurrentNode = m_ParentStack.top();
		m_ParentStack.pop();

		//	トップ階層でなければ次に進む
		if( !m_ParentStack.empty() ) { NextNode(); }
	}

	/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
	//! 同じ階層のノードを作成する
	/*!
	*/
	void CXMLWriter::NextNode()
	{
		MAID_ASSERT( m_ParentStack.empty(), "トップ階層のノードは１つだけです" );
		MAID_ASSERT( m_pCurrentNode->GetElementName().empty(), "要素名を決める必要があります" );

		SPXMLNODE pNew( new CXMLNode );
		m_ParentStack.top()->AddChildNode( pNew );
		m_pCurrentNode = pNew;
	}

	void CXMLWriter::SetElementName( const mstring& name )
	{
		m_pCurrentNode->SetElementName( name );
	}

	void CXMLWriter::SetValueText( const mstring& value )
	{
		SPXMLNODE pNew( new CXMLNode );
		pNew->SetText( value );

		SetValue( pNew );
	}

	void CXMLWriter::SetValueFloat( float value )
	{
		SPXMLNODE pNew( new CXMLNode );
		pNew->SetText( CString::FtoA(value) );
		SetValue( pNew );
	}

	void CXMLWriter::SetValueInt( int value )
	{
		SPXMLNODE pNew( new CXMLNode );
		pNew->SetText( CString::ItoA(value) );
		SetValue( pNew );
	}

	void CXMLWriter::SetValue( const SPXMLNODE& pNode )
	{
		if( m_pCurrentNode->GetChildLength()==0 )
		{
			m_pCurrentNode->AddChildNode( pNode );
		}else
		{
			m_pCurrentNode->SetChildNode(0,pNode);
		}
	}


	void CXMLWriter::AddAttribute( const mstring& name, const mstring& value )
	{
		m_pCurrentNode->SetAttribute( name, value );
	}

	void CXMLWriter::AddAttribute( const mstring& name, const float& value )
	{
		m_pCurrentNode->SetAttribute( name, CString::FtoA(value) );
	}

	void CXMLWriter::AddAttribute( const mstring& name, const int& value )
	{
		m_pCurrentNode->SetAttribute( name, CString::ItoA(value) );
	}

	void CXMLWriter::SetTag ( const mstring& element, const mstring& value )
	{
		SetElementName( element );
		SetValueText( value );
	}

	void CXMLWriter::SetTag( const mstring& element, const float& value )
	{
		SetElementName( element );
		SetValueFloat( value );
	}

	void CXMLWriter::SetTag  ( const mstring& element, const int&   value )
	{
		SetElementName( element );
		SetValueInt( value );
	}

	void CXMLWriter::Save( const mstring& FileName )
	{
		//	ルートノードまで上る
		while( !m_ParentStack.empty() )
		{
			DescendNode();
		}

		//	お決まりの文字
		mstring text = MAIDTEXT("<?xml version=\"1.0\" encoding=\"shift_jis\"?>\n");

		ConvertSaveText( *m_pCurrentNode, text );

		const MySTL::string sjis = CString::ConvertMAIDtoSJIS(text);

		CFileWrite::Write( FileName, sjis.c_str(), (int)sjis.length() );
	}

	void CXMLWriter::Save( MySTL::vector<unt08>& FileImage )
	{
		//	ルートノードまで上る
		while( !m_ParentStack.empty() )
		{
			DescendNode();
		}

		//	お決まりの文字
		mstring text = MAIDTEXT("<?xml version=\"1.0\" encoding=\"shift_jis\"?>\n");

		ConvertSaveText( *m_pCurrentNode, text );

		const MySTL::string sjis = CString::ConvertMAIDtoSJIS(text);

		FileImage.resize( sjis.length() );

		::memcpy( &FileImage[0], sjis.c_str(), sjis.length() );
	}


	void CXMLWriter::ConvertSaveText( const CXMLNode& Node, mstring& text )
	{
		const CXMLNode::TYPE type = Node.GetType();

		switch( type )
		{
		case CXMLNode::TYPE_EMPTY:	{ }break;
		case CXMLNode::TYPE_TEXT:
			{
				const mstring name = Node.GetText().GetStr();
				text += name;
			}break;

		case CXMLNode::TYPE_ELEMENT:
			{
				const mstring ElementName = Node.GetElementName();
				
				{

					text += MAIDTEXT("<") + ElementName;
					CXMLNode::ATTRIBUTELIST List = Node.GetAttributeTable();

					for( CXMLNode::ATTRIBUTELIST::const_iterator ite = List.begin();
									ite!=List.end(); ++ite )
					{
						const mstring name = ite->first;
						const mstring vale = ite->second.GetStr();

						text += MAIDTEXT(" ")+ name + MAIDTEXT("=\"") + vale + MAIDTEXT("\"");
					}
					text += MAIDTEXT(">");
				}


				for( int i=0; i<Node.GetChildLength(); ++i )
				{
					CXMLNode& node = Node.GetChildNode( i );
					ConvertSaveText( node, text );
				}

				text += MAIDTEXT("</") + ElementName + MAIDTEXT(">\n");
			}break;

		case CXMLNode::TYPE_COMMENT:{ }break;
		}

	}

}

