// aplXML.h

//  APLXML
#include <afxtempl.h>

#ifndef APLXML
#define APLXML


#ifndef APL_XML_PARSER_NOAUTOLIB
#ifdef _DEBUG
#ifdef UNICODE
#pragma comment (lib,"aplXMLParser_ud.lib")
#else
#pragma comment (lib,"aplXMLParserD.lib")
#endif
#else
#ifdef UNICODE
#pragma comment (lib,"aplXMLParser_u.lib")
#else
#pragma comment (lib,"aplXMLParser.lib")
#endif
#endif
#endif


class CaplXMLNode;
class CaplXMLFile;

typedef CArray <CaplXMLNode*, CaplXMLNode*> APL_XML_NODES;

class AFX_CLASS_EXPORT CaplXMLNode
{
public:

	class AFX_CLASS_EXPORT CaplXMLParam
	{
	public:
		CString name;
		CString value;

		CaplXMLParam(LPCTSTR paramname, LPCTSTR paramvalue) {name=paramname; value=paramvalue;};
		CaplXMLParam(LPCTSTR paramname, LPWSTR paramvalue) {name=paramname; value=paramvalue;};
		CaplXMLParam(){};
	};

	CString name;
	CString text;
	
	CaplXMLNode *parent;
	CArray <CaplXMLParam, CaplXMLParam&> params;
	CArray <CaplXMLNode*, CaplXMLNode*> subnodes;

	CaplXMLFile* m_file;	

	CaplXMLNode(){parent=0;m_file= 0;};
	CaplXMLNode(LPCTSTR nodename, CaplXMLNode *nodeparent=0, CaplXMLFile* file=0);

	~CaplXMLNode();
	void Clear();
	
	void SetName(LPCTSTR name);	

	//выгрузка если значение не пустое/не нулевое 
	void SetParamIfNotEmpty(LPCTSTR paramname, LPCTSTR paramvalue, bool bNoFindExist=false);
	void SetParamIfNotEmpty(LPCTSTR paramname, double paramvalue, bool bNoFindExist = false);
	void SetParamIfNotEmpty(LPCTSTR paramname, float paramvalue, bool bNoFindExist = false);
	void SetParamIfNotEmpty(LPCTSTR paramname, int paramvalue, bool bNoFindExist = false);
	void SetParamIfNotEmpty(LPCTSTR paramname, long paramvalue, bool bNoFindExist = false);
	void SetParamIfNotEmpty(LPCTSTR paramname, LPWSTR  paramvalue, bool bNoFindExist = false);

	/// Устанавливает значение параметра. Если bNoFindExist == true, бобавляет не проверяя наличие.
	void SetParam(LPCTSTR paramname, LPCTSTR paramvalue, bool bNoFindExist=false);	
	void SetParam(LPCTSTR paramname, double paramvalue, bool bNoFindExist=false);	
	void SetParam(LPCTSTR paramname, float paramvalue, bool bNoFindExist=false);	
	void SetParam(LPCTSTR paramname, int paramvalue, bool bNoFindExist=false);
	void SetParam(LPCTSTR paramname, long paramvalue, bool bNoFindExist=false);
	void SetParam(LPCTSTR paramname, bool paramvalue, bool bNoFindExist=false);
	void SetParam(LPCTSTR paramname, LPWSTR  paramvalue, bool bNoFindExist=false);

	LPCTSTR GetParam(LPCTSTR paramname);
	bool CheckParam(LPCTSTR paramname);


	void GetParam(LPCTSTR paramname, bool& bVal);
	void GetParam(LPCTSTR paramname, int& iVal);
	void GetParam(LPCTSTR paramname, long& lVal);
	void GetParam(LPCTSTR paramname, double& dVal);
	void GetParam(LPCTSTR paramname, float& fVal);
	void GetParam(LPCTSTR paramname, CString& sVal);
	
	double GetDoubleParam(LPCTSTR paramname);
	int GetIntParam(LPCTSTR paramname);
	long GetLongParam(LPCTSTR paramname);
	bool GetBoolParam( LPCTSTR paramname );

	//CString FormatNode(bool bUseLevel= false, int iLevel= 0);

	// Ищет node удовлетворяющие условию вложения a'la xpath
	// Например: "catalog/cd/price" 
	// Вместо имени в цепочке может стоять * (для первого имени * смысла не имеет)
	bool Find(LPCTSTR query, APL_XML_NODES &resultnodes);

	// возвращает все node с именем sNodeName, начиная с текущего
	// bRecursive - искать внутри  sNodeName другие sNodeName с тем-же именем
	bool FindNodesBN(LPCTSTR sNodeName, APL_XML_NODES &resultnodes, bool bRecursive=false);

	// Ищет первый входящий Node с именем sNodeName
	CaplXMLNode *FindSingleNodeBN(LPCTSTR sNodeName);

protected:
	bool FindNodesBNinternal(LPCTSTR sNodeName, APL_XML_NODES &resultnodes, bool bRecursive=false);
};

class AFX_CLASS_EXPORT CaplXMLFile
{
public:
		class AFX_CLASS_EXPORT aplXMLReadBuf
		{
		public:

			char *buf;
			DWORD len;
			DWORD pos;
			int line;
			int pos_in_line;
			CaplXMLFile* m_pXMLFile;

			aplXMLReadBuf(CaplXMLFile* xmlFile);
			~aplXMLReadBuf();

			bool ReadFile(LPCTSTR path, bool bDenyWrite = true, bool bShowErrors = true);
			bool Init(LPCTSTR inBuf = NULL);

			bool GetNode(CaplXMLNode &node);

			bool GetChar( char &c, bool IsStr=false);
			//bool GetChar( char &c,bool IsStr=false, bool bIgnoreNewLine=false);
			bool IgnoreSpacer();

			void ChangePos(int delta){pos+=delta;}

			bool ConvertSpecSymbolFromBuf(char &c, char& cExt );

		protected:
				// Используются в GetNode для избежания лишних выделений памяти 
			CStringA m_param;
			CStringA m_value;
			CStringA m_end_tag_name;

			LPWSTR m_stmp; 
			int m_stmp_len;


		};
protected:
	bool m_bIsFileOpen;
	bool Read(aplXMLReadBuf* xmlBufer);


public:
	bool ConvertToUTF8(CString &str);
	
	CString filename;
	CString xmlversion;
	CString filecharset;
	CString additionalheader; //<?mso-application progid="Excel.Sheet"?>
	CString sReportName;		// имя отчета (для КВЗ)
	
	bool m_bIsUtf8;  //Используется только при чтении
	bool m_bSaveBOM;	// При записи (вообще для UTF-8 писать BOM для XML не очень то надо, но пусть останется с возможностью отключения)
	bool m_bTrimStrValues; //Удаление пробелов\табуляций в конце текста у значений строковых атрибутов XML

	bool m_bNoMessageBox; //Если true, то сообщения отображаются не в виде AfxMessageBox, а пишутся в переменную m_sErrMessage
	CString m_sErrMessage; // Сюда пишутся сообщения вместо AfxMessageBox, если m_bNoMessageBox==true;

	bool m_bIgnoreQuotesInContent; // если true - кавычки в содержании тега игнорируются (по стандарту их быть вообще не должно) по умолчанию = false

	CaplXMLNode root;	

	CaplXMLFile(bool bIsUtf8 = true, bool bSaveBOM = true);//{m_bCheckParamUnique=true;};

	bool IsFileOpen(){return m_bIsFileOpen;}
	void TrimValues(bool bTrimStrValues) { m_bTrimStrValues = bTrimStrValues; }

	bool LoadFromFile(LPCTSTR path,bool bDenyWrite=true, bool bShowErrors = true);
	bool LoadFromBuffer(LPCTSTR buffer);

	// bSaveXmlVer - писать или нет <?xml version="1.0"
	bool SaveToFile(LPCTSTR path, bool bSaveXmlVer = true, bool bShowErrors = true, bool bUTF8 = false);
	bool SaveToFileAsParams(LPCTSTR path, bool bSaveXmlVer = true);

	// bSaveXmlVer - писать или нет <?xml version="1.0"
	bool SaveToBuffer(CString &buffer, bool bSaveXmlVer = true, CStdioFile *file = 0);
	bool SaveToBufferAsParams(CString &buffer, bool bSaveXmlVer = true, CStdioFile *file = 0);
	
	// level - уровень, используется для установки отступов
	// если level==-1, то отступы не делаются
	bool SaveNode(CString &buffer, CaplXMLNode &node, int level=0, CStdioFile *file=NULL);
	bool SaveNodeParams(CString &buffer, CaplXMLNode &node, int level=0, CStdioFile *file=NULL);

	static bool ReplaceSpecSymbol(CString &in, CString &out, bool bAppendOut);	

	// Преобразует blob в base64
	static bool EncodeToBase64( unsigned char const* BYTEs_to_encode, unsigned int in_len, CString &out_string ); 
	// Преобразует строку base64 в blob. Если buf==0 возвращает длинну
	static bool DecodeFromBase64(LPCTSTR encoded_string, unsigned char const *buf, unsigned int &buf_len);
};

#endif