/******************************************************************************
 *
 * Project:  NAS Reader
 * Purpose:  Private Declarations for OGR NAS Reader code.
 * Author:   Frank Warmerdam, warmerdam@pobox.com
 *
 ******************************************************************************
 * Copyright (c) 2008, Frank Warmerdam
 * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
 *
 * SPDX-License-Identifier: MIT
 ****************************************************************************/

#ifndef CPL_NASREADERP_H_INCLUDED
#define CPL_NASREADERP_H_INCLUDED

#include "xercesc_headers.h"
#include "ogr_xerces.h"

#include "gmlreader.h"
#include "gmlreaderp.h"
#include "ogr_api.h"
#include "ogr_geometry.h"
#include "cpl_string.h"
#include <list>

IGMLReader *CreateNASReader();

class NASReader;

CPL_C_START
OGRGeometryH OGR_G_CreateFromGML3(const char *pszGML);
CPL_C_END

/************************************************************************/
/*                              NASHandler                              */
/************************************************************************/
class NASHandler final : public DefaultHandler
{
    NASReader *m_poReader;

    char *m_pszCurField;

    char *m_pszGeometry;
    int m_nGeomAlloc;
    int m_nGeomLen;

    int m_nGeometryDepth;
    int m_nGeometryPropertyIndex;
    bool IsGeometryElement(const char *);

    int m_nDepth;
    int m_nDepthFeature;
    bool m_bIgnoreFeature;

    CPLString m_osDeleteContext;
    CPLString m_osTypeName;
    CPLString m_osReplacingFID;
    CPLString m_osSafeToIgnore;
    CPLString m_osUpdatePropertyName;
    CPLString m_osUpdateEnds;
    CPLString m_osFeatureId;
    std::list<CPLString> m_UpdateOccasions;

    CPLString m_osElementName;
    CPLString m_osCharacters;

    const Locator *m_Locator;

    int m_nEntityCounter = 0;

  public:
    explicit NASHandler(NASReader *poReader);
    ~NASHandler() override;

    void startElement(const XMLCh *const uri, const XMLCh *const localname,
                      const XMLCh *const qname,
                      const Attributes &attrs) override;
    void endElement(const XMLCh *const uri, const XMLCh *const localname,
                    const XMLCh *const qname) override;
#if XERCES_VERSION_MAJOR >= 3
    void characters(const XMLCh *const chars, const XMLSize_t length) override;
#else
    void characters(const XMLCh *const chars, const unsigned int length);
#endif

    void fatalError(const SAXParseException &) override;

    void startEntity(const XMLCh *const name) override;

    void setDocumentLocator(const Locator *locator) override;

    CPLString GetAttributes(const Attributes *attr);
};

/************************************************************************/
/*                             GMLReadState                             */
/************************************************************************/

// for now, use existing gmlreadstate.
#ifdef notdef
class GMLReadState
{
    void RebuildPath();

  public:
    GMLReadState();
    ~GMLReadState();

    void PushPath(const char *pszElement);
    void PopPath();

    int MatchPath(const char *pszPathInput);

    const char *GetPath() const
    {
        return m_pszPath;
    }

    const char *GetLastComponent() const;

    GMLFeature *m_poFeature;
    GMLReadState *m_poParentState;

    char *m_pszPath;  // element path ... | as separator.

    int m_nPathLength;
    char **m_papszPathComponents;
};
#endif

/************************************************************************/
/*                              NASReader                               */
/************************************************************************/

class NASReader final : public IGMLReader
{
  private:
    bool m_bClassListLocked;

    int m_nClassCount;
    GMLFeatureClass **m_papoClass;

    char *m_pszFilename;

    NASHandler *m_poNASHandler;
    SAX2XMLReader *m_poSAXReader;
    bool m_bReadStarted;
    bool m_bXercesInitialized;
    XMLPScanToken m_oToFill;

    GMLReadState *m_poState;

    GMLFeature *m_poCompleteFeature;
    VSILFILE *m_fp;
    InputSource *m_GMLInputSource;

    bool SetupParser();
    void CleanupParser();

    char *m_pszFilteredClassName;
    bool m_bStopParsing = false;

  public:
    NASReader();
    ~NASReader() override;

    bool IsClassListLocked() const override
    {
        return m_bClassListLocked;
    }

    void SetClassListLocked(bool bFlag) override
    {
        m_bClassListLocked = bFlag;
    }

    void SetSourceFile(const char *pszFilename) override;
    const char *GetSourceFileName() override;

    int GetClassCount() const override
    {
        return m_nClassCount;
    }

    GMLFeatureClass *GetClass(int i) const override;
    GMLFeatureClass *GetClass(const char *pszName) const override;

    int AddClass(GMLFeatureClass *poClass) override;
    void ClearClasses() override;

    GMLFeature *NextFeature() override;

    bool LoadClasses(const char *pszFile = nullptr) override;
    bool SaveClasses(const char *pszFile = nullptr) override;

    bool PrescanForSchema(bool bGetExtents = true,
                          bool bOnlyDetectSRS = false) override;
    bool PrescanForTemplate() override;
    void ResetReading() override;

    bool ParseXSD(const char * /* pszFile */)
    {
        return false;
    }

    bool ResolveXlinks(const char *pszFile, bool *pbOutIsTempFile,
                       char **papszSkip = nullptr,
                       const bool bStrict = false) override;

    bool HugeFileResolver(const char *pszFile, bool bSqliteIsTempFile,
                          int iSqliteCacheMB) override;

    // ---

    GMLReadState *GetState() const
    {
        return m_poState;
    }

    void PopState();
    void PushState(GMLReadState *);

    bool IsFeatureElement(const char *pszElement);
    bool IsAttributeElement(const char *pszElement, const Attributes &attrs);

    void PushFeature(const char *pszElement, const Attributes &attrs);

    void SetFeaturePropertyDirectly(const char *pszElement, char *pszValue);

    void StopParsing()
    {
        m_bStopParsing = true;
    }

    bool HasStoppedParsing() override
    {
        return m_bStopParsing;
    }

    int GetAttributeElementIndex(const char *pszElement, int nLen,
                                 const char *pszAttrKey);
    void DealWithAttributes(const char *pszElement, int nLenName,
                            const Attributes &attrs);

    const char *GetGlobalSRSName() override
    {
        return nullptr;
    }

    bool CanUseGlobalSRSName() override
    {
        return false;
    }

    bool SetFilteredClassName(const char *pszClassName) override;

    const char *GetFilteredClassName() override
    {
        return m_pszFilteredClassName;
    }

    static OGRGeometry *ConvertGeometry(OGRGeometry *);
};

#endif /* CPL_NASREADERP_H_INCLUDED */
