/**
@filename expat_ex.hpp
@brief expatを使いXML処理の補助
@note

*/

#ifndef DKUTIL_EXPAT_EX_HPP
#define DKUTIL_EXPAT_EX_HPP



#include <dkutil/parser/expat_xml_parser.hpp>
#include <dkutil/filesystem/big_filestream.hpp>

namespace dkutil{

	template<class POLICY_T>
	class expat_file_read_interface : public expat_parser_interface<POLICY_T>
	{
	public:
		typedef typename POLICY_T policy_type;
		typedef typename expat_file_read_interface<POLICY_T> self_type;
		typedef typename expat_parser_interface<POLICY_T> base_type;
		expat_file_read_interface(){}
		~expat_file_read_interface(){}
		/**
		@return succeeded == 0
						file error == -1
						parse error == -2
		*/
		template<class FUNCTOR>
		int parse_file_with_functor(path_string_ref filename,FUNCTOR functor,
			bool istext=false,size_t inner_buffer_size=1024 * 32)
		{
			big_filestream stream;
			UINT flag = (istext) ? text_mode : binary_mode;
			flag |= read_mode;
			bool r = stream.reset(filename,flag );
			if(false==r) return -1;
			r = stream.open();
			if(false==r) return -1;
			size_t filesize = stream.filesize();

			scoped_buffer_char buff;
			if(buff.reset(inner_buffer_size)==false)
				return false;
			

			int tr;
			size_t readsize;
			for(;;){
				if(stream.error()){
					std::string s = string_nprintf(1024,
						"expat_parser_interface<>::parse_file( %s ) filestream reading error"
					);
					DKUTIL_THROW_OR_NOTICE(filesystem_error(s));
					return -1;
				}
				readsize = stream.read(buff.get(),buff.size());
				functor(buff.get(),readsize,filesize);
				if(stream.eof()){
					tr = XML_Parse(buff.get(),readsize,TRUE);
					break;
				}else{
					tr = XML_Parse(buff.get(),readsize,FALSE);
				}  
				switch(tr){
				case XML_STATUS_ERROR:
					return -2;
					break;
				case XML_STATUS_OK:
					break;
				case XML_STATUS_SUSPENDED:
					break;
				}
			}
			tr = XML_GetErrorCode();
#if defined(DEBUG) || defined(_DEBUG)
			if(XML_ERROR_NONE != tr){
				dump("expat_xml_error.xml",buff.get(),readsize,true);
			}
#endif

			//0==succeeded
			
			return (XML_ERROR_NONE == tr) ? 0 : -2;
		}


		struct parse_null_functor{
			void operator()(const char *buff,size_t size,size_t allsize)
			{

			}
		};
		int parse_file(path_string_ref filename,
			bool istext=false,size_t inner_buffer_size=1024 * 32)
		{
			return parse_file_with_functor(filename,parse_null_functor(),istext,inner_buffer_size);

		}
	};
	typedef expat_file_read_interface<policy::expat_parser_deque_container_policy> expat_xml_parser_deque;

}//end of dkutil namespace



#endif
