text: /*
   * Copyright (C) 2004-2015 ZNC, see the NOTICE file for details.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #ifndef _TEMPLATE_H
  #define _TEMPLATE_H
  
  #include <znc/zncconfig.h>
  #include <znc/ZNCString.h>
  #include <iostream>
  #include <list>
  #include <memory>
  
  class CTemplate;
  
  class CTemplateTagHandler {
  public:
  	CTemplateTagHandler() {}
  	virtual ~CTemplateTagHandler() {}
  
  	virtual bool HandleVar(CTemplate& Tmpl, const CString& sName, const CString& sArgs, CString& sOutput) {
  		return false;
  	}
  
  	virtual bool HandleTag(CTemplate& Tmpl, const CString& sName, const CString& sArgs, CString& sOutput) {
  		return false;
  	}
  
  	virtual bool HandleIf(CTemplate& Tmpl, const CString& sName, const CString& sArgs, CString& sOutput) {
  		return HandleVar(Tmpl, sName, sArgs, sOutput);
  	}
  
  	virtual bool HandleValue(CTemplate& Tmpl, CString& sValue, const MCString& msOptions) {
  		return false;
  	}
  private:
  };
  class CTemplate;
  
  class CTemplateOptions {
  public:
  	CTemplateOptions() {
  		m_eEscapeFrom = CString::EASCII;
  		m_eEscapeTo = CString::EASCII;
  	}
  
  	virtual ~CTemplateOptions() {}
  
  	void Parse(const CString& sLine);
  
  	// Getters
  	CString::EEscape GetEscapeFrom() const { return m_eEscapeFrom; }
  	CString::EEscape GetEscapeTo() const { return m_eEscapeTo; }
  	// !Getters
  private:
  	CString::EEscape   m_eEscapeFrom;
  	CString::EEscape   m_eEscapeTo;
  };
  
  
  class CTemplateLoopContext {
  public:
  	CTemplateLoopContext(unsigned long uFilePos, const CString& sLoopName, bool bReverse, std::vector<CTemplate*>* pRows) {
  		m_uFilePosition = uFilePos;
  		m_sName = sLoopName;
  		m_uRowIndex = 0;
  		m_bReverse = bReverse;
  		m_pvRows = pRows;
  		m_bHasData = false;
  	}
  
  	virtual ~CTemplateLoopContext() {}
  
  	// Setters
  	void SetHasData(bool b = true) { m_bHasData = b; }
  	void SetName(const CString& s) { m_sName = s; }
  	void SetRowIndex(unsigned int u) { m_uRowIndex = u; }
  	unsigned int IncRowIndex() { return ++m_uRowIndex; }
  	unsigned int DecRowIndex() { if (m_uRowIndex == 0) { return 0; } return --m_uRowIndex; }
  	void SetFilePosition(unsigned int u) { m_uFilePosition = u; }
  	// !Setters
  
  	// Getters
  	bool HasData() const { return m_bHasData; }
  	const CString& GetName() const { return m_sName; }
  	unsigned long GetFilePosition() const { return m_uFilePosition; }
  	unsigned int GetRowIndex() const { return m_uRowIndex; }
  	size_t GetRowCount() { return m_pvRows->size(); }
  	std::vector<CTemplate*>* GetRows() { return m_pvRows; }
  	CTemplate* GetNextRow() { return GetRow(IncRowIndex()); }
  	CTemplate* GetCurRow() { return GetRow(m_uRowIndex); }
  
  	CTemplate* GetRow(unsigned int uIndex);
  	CString GetValue(const CString& sName, bool bFromIf = false);
  	// !Getters
  private:
  	bool                  m_bReverse;       //!< Iterate through this loop in reverse order
  	bool                  m_bHasData;       //!< Tells whether this loop has real data or not
  	CString               m_sName;          //!< The name portion of the <?LOOP name?> tag
  	unsigned int          m_uRowIndex;      //!< The index of the current row we're on
  	unsigned long         m_uFilePosition;  //!< The file position of the opening <?LOOP?> tag
  	std::vector<CTemplate*>*   m_pvRows;         //!< This holds pointers to the templates associated with this loop
  };
  
  
  class CTemplate : public MCString {
  public:
  	CTemplate() : MCString(), m_spOptions(new CTemplateOptions) {
  		Init();
  	}
  
  	CTemplate(const CString& sFileName) : MCString(), m_sFileName(sFileName), m_spOptions(new CTemplateOptions) {
  		Init();
  	}
  
  	CTemplate(const std::shared_ptr<CTemplateOptions>& Options, CTemplate* pParent = NULL) : MCString(), m_spOptions(Options) {
  		Init();
  		m_pParent = pParent;
  	}
  
  	virtual ~CTemplate();
  
  	//! Class for implementing custom tags in subclasses
  	void AddTagHandler(std::shared_ptr<CTemplateTagHandler> spTagHandler) {
  		m_vspTagHandlers.push_back(spTagHandler);
  	}
  
  	std::vector<std::shared_ptr<CTemplateTagHandler> >& GetTagHandlers() {
  		if (m_pParent) {
  			return m_pParent->GetTagHandlers();
  		}
  
  		return m_vspTagHandlers;
  	}
  
  	CString ResolveLiteral(const CString& sString);
  
  	void Init();
  
  	CTemplate* GetParent(bool bRoot);
  	CString ExpandFile(const CString& sFilename, bool bFromInc = false);
  	bool SetFile(const CString& sFileName);
  
  	void SetPath(const CString& sPath);  // Sets the dir:dir:dir type path to look at for templates, as of right now no ../../.. protection
  	CString MakePath(const CString& sPath) const;
  	void PrependPath(const CString& sPath, bool bIncludesOnly = false);
  	void AppendPath(const CString& sPath, bool bIncludesOnly = false);
  	void RemovePath(const CString& sPath);
  	void ClearPaths();
  	bool PrintString(CString& sRet);
  	bool Print(std::ostream& oOut);
  	bool Print(const CString& sFileName, std::ostream& oOut);
  	bool ValidIf(const CString& sArgs);
  	bool ValidExpr(const CString& sExpr);
  	bool IsTrue(const CString& sName);
  	bool HasLoop(const CString& sName);
  	CString GetValue(const CString& sName, bool bFromIf = false);
  	CTemplate& AddRow(const CString& sName);
  	CTemplate* GetRow(const CString& sName, unsigned int uIndex);
  	std::vector<CTemplate*>* GetLoop(const CString& sName);
  	void DelCurLoopContext();
  	CTemplateLoopContext* GetCurLoopContext();
  	CTemplate* GetCurTemplate();
  
  	// Getters
  	const CString& GetFileName() const { return m_sFileName; }
  	// !Getters
  private:
  	CTemplate*                               m_pParent;
  	CString                                  m_sFileName;
  	std::list<std::pair<CString, bool> >               m_lsbPaths;
  	std::map<CString, std::vector<CTemplate*> >        m_mvLoops;
  	std::vector<CTemplateLoopContext*>            m_vLoopContexts;
  	std::shared_ptr<CTemplateOptions>              m_spOptions;
  	std::vector<std::shared_ptr<CTemplateTagHandler> >  m_vspTagHandlers;
  };
  
  #endif // !_TEMPLATE_H
  