// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#ifndef XFA_FXFA_PARSER_XFA_UTILS_H_
#define XFA_FXFA_PARSER_XFA_UTILS_H_

#include "xfa/fde/xml/fde_xml.h"
#include "xfa/fxfa/include/fxfa_basic.h"

class CFDE_XMLElement;
class CFDE_XMLNode;
class CXFA_LocaleValue;

inline FX_BOOL XFA_IsSpace(FX_WCHAR c) {
  return (c == 0x20) || (c == 0x0d) || (c == 0x0a) || (c == 0x09);
}
inline FX_BOOL XFA_IsDigit(FX_WCHAR c) {
  return c >= '0' && c <= '9';
}

FX_BOOL XFA_FDEExtension_ResolveNamespaceQualifier(
    CFDE_XMLElement* pNode,
    const CFX_WideStringC& wsQualifier,
    CFX_WideString& wsNamespaceURI);
template <class NodeType, class TraverseStrategy>
class CXFA_NodeIteratorTemplate {
 public:
  CXFA_NodeIteratorTemplate(NodeType* pRootNode = NULL) : m_pRoot(pRootNode) {
    if (pRootNode) {
      m_NodeStack.Push(pRootNode);
    }
  }
  FX_BOOL Init(NodeType* pRootNode) {
    if (!pRootNode) {
      return FALSE;
    }
    m_pRoot = pRootNode;
    m_NodeStack.RemoveAll();
    m_NodeStack.Push(pRootNode);
    return TRUE;
  }
  void Clear() { m_NodeStack.RemoveAll(); }
  void Reset() {
    Clear();
    if (m_pRoot) {
      m_NodeStack.Push(m_pRoot);
    }
  }
  FX_BOOL SetCurrent(NodeType* pCurNode) {
    m_NodeStack.RemoveAll();
    if (pCurNode) {
      CFX_StackTemplate<NodeType*> revStack;
      NodeType* pNode;
      for (pNode = pCurNode; pNode && pNode != m_pRoot;
           pNode = TraverseStrategy::GetParent(pNode)) {
        revStack.Push(pNode);
      }
      if (!pNode) {
        return FALSE;
      }
      revStack.Push(m_pRoot);
      while (revStack.GetSize()) {
        m_NodeStack.Push(*revStack.GetTopElement());
        revStack.Pop();
      }
    }
    return TRUE;
  }
  NodeType* GetCurrent() const {
    return m_NodeStack.GetSize() ? *m_NodeStack.GetTopElement() : NULL;
  }
  NodeType* GetRoot() const { return m_pRoot; }
  NodeType* MoveToPrev() {
    int32_t nStackLength = m_NodeStack.GetSize();
    if (nStackLength == 1) {
      return NULL;
    } else if (nStackLength > 1) {
      NodeType* pCurItem = *m_NodeStack.GetTopElement();
      m_NodeStack.Pop();
      NodeType* pParentItem = *m_NodeStack.GetTopElement();
      NodeType* pParentFirstChildItem =
          TraverseStrategy::GetFirstChild(pParentItem);
      if (pCurItem == pParentFirstChildItem) {
        return pParentItem;
      }
      NodeType *pPrevItem = pParentFirstChildItem, *pPrevItemNext = NULL;
      for (; pPrevItem; pPrevItem = pPrevItemNext) {
        pPrevItemNext = TraverseStrategy::GetNextSibling(pPrevItem);
        if (!pPrevItemNext || pPrevItemNext == pCurItem) {
          break;
        }
      }
      m_NodeStack.Push(pPrevItem);
    } else {
      m_NodeStack.RemoveAll();
      if (m_pRoot) {
        m_NodeStack.Push(m_pRoot);
      }
    }
    if (m_NodeStack.GetSize() > 0) {
      NodeType* pChildItem = *m_NodeStack.GetTopElement();
      while ((pChildItem = TraverseStrategy::GetFirstChild(pChildItem)) !=
             NULL) {
        while (NodeType* pNextItem =
                   TraverseStrategy::GetNextSibling(pChildItem)) {
          pChildItem = pNextItem;
        }
        m_NodeStack.Push(pChildItem);
      }
      return *m_NodeStack.GetTopElement();
    }
    return NULL;
  }
  NodeType* MoveToNext() {
    NodeType** ppNode = NULL;
    NodeType* pCurrent = GetCurrent();
    while (m_NodeStack.GetSize() > 0) {
      while ((ppNode = m_NodeStack.GetTopElement())) {
        if (pCurrent != *ppNode) {
          return *ppNode;
        }
        NodeType* pChild = TraverseStrategy::GetFirstChild(*ppNode);
        if (pChild == NULL) {
          break;
        }
        m_NodeStack.Push(pChild);
      }
      while ((ppNode = m_NodeStack.GetTopElement())) {
        NodeType* pNext = TraverseStrategy::GetNextSibling(*ppNode);
        m_NodeStack.Pop();
        if (m_NodeStack.GetSize() == 0) {
          break;
        }
        if (pNext) {
          m_NodeStack.Push(pNext);
          break;
        }
      }
    }
    return NULL;
  }
  NodeType* SkipChildrenAndMoveToNext() {
    NodeType** ppNode = NULL;
    while ((ppNode = m_NodeStack.GetTopElement())) {
      NodeType* pNext = TraverseStrategy::GetNextSibling(*ppNode);
      m_NodeStack.Pop();
      if (m_NodeStack.GetSize() == 0) {
        break;
      }
      if (pNext) {
        m_NodeStack.Push(pNext);
        break;
      }
    }
    return GetCurrent();
  }

 protected:
  NodeType* m_pRoot;
  CFX_StackTemplate<NodeType*> m_NodeStack;
};
template <class KeyType>
class CXFA_PtrSetTemplate : private CFX_MapPtrToPtr {
 public:
  CXFA_PtrSetTemplate() : CFX_MapPtrToPtr(10) {}

  int GetCount() const { return CFX_MapPtrToPtr::GetCount(); }

  FX_BOOL IsEmpty() const { return CFX_MapPtrToPtr::IsEmpty(); }

  FX_BOOL Lookup(KeyType key) const {
    void* pValue = NULL;
    return CFX_MapPtrToPtr::Lookup((void*)key, pValue);
  }

  FX_BOOL operator[](KeyType key) { return Lookup(key); }

  void Add(KeyType key) { CFX_MapPtrToPtr::SetAt((void*)key, (void*)key); }

  FX_BOOL RemoveKey(KeyType key) {
    return CFX_MapPtrToPtr::RemoveKey((void*)key);
  }

  void RemoveAll() { CFX_MapPtrToPtr::RemoveAll(); }

  FX_POSITION GetStartPosition() const {
    return CFX_MapPtrToPtr::GetStartPosition();
  }

  void GetNextAssoc(FX_POSITION& rNextPosition, KeyType& rKey) const {
    void* pKey = NULL;
    void* pValue = NULL;
    CFX_MapPtrToPtr::GetNextAssoc(rNextPosition, pKey, pValue);
    rKey = (KeyType)(uintptr_t)pKey;
  }
};
class CXFA_Node;
class CXFA_WidgetData;

CXFA_Node* XFA_CreateUIChild(CXFA_Node* pNode, XFA_ELEMENT& eWidgetType);
CXFA_LocaleValue XFA_GetLocaleValue(CXFA_WidgetData* pWidgetData);
FX_DOUBLE XFA_WideStringToDouble(const CFX_WideString& wsStringVal);
FX_DOUBLE XFA_ByteStringToDouble(const CFX_ByteStringC& szStringVal);
int32_t XFA_MapRotation(int32_t nRotation);

FX_BOOL XFA_RecognizeRichText(CFDE_XMLElement* pRichTextXMLNode);
void XFA_GetPlainTextFromRichText(CFDE_XMLNode* pXMLNode,
                                  CFX_WideString& wsPlainText);
FX_BOOL XFA_FieldIsMultiListBox(CXFA_Node* pFieldNode);
IFX_Stream* XFA_CreateWideTextRead(const CFX_WideString& wsBuffer);
FX_BOOL XFA_IsLayoutElement(XFA_ELEMENT eElement,
                            FX_BOOL bLayoutContainer = FALSE);

void XFA_DataExporter_DealWithDataGroupNode(CXFA_Node* pDataNode);
void XFA_DataExporter_RegenerateFormFile(CXFA_Node* pNode,
                                         IFX_Stream* pStream,
                                         const FX_CHAR* pChecksum = NULL,
                                         FX_BOOL bSaveXML = FALSE);

#endif  // XFA_FXFA_PARSER_XFA_UTILS_H_
