/******************************************************************************
 * $Id: ogr_edigeo.h bc3d9f5351962c422f3e57a9ab1a251d91659192 2020-05-09 21:07:14 +0200 Even Rouault $
 *
 * Project:  EDIGEO Translator
 * Purpose:  Definition of classes for OGR .edigeo driver.
 * Author:   Even Rouault, even dot rouault at spatialys.com
 *
 ******************************************************************************
 * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ****************************************************************************/

#ifndef OGR_EDIGEO_H_INCLUDED
#define OGR_EDIGEO_H_INCLUDED

#include "ogrsf_frmts.h"
#include <vector>
#include <map>
#include <set>

/************************************************************************/
/*                           OGREDIGEOLayer                             */
/************************************************************************/

class OGREDIGEODataSource;

class OGREDIGEOLayer final: public OGRLayer, public OGRGetNextFeatureThroughRaw<OGREDIGEOLayer>
{
    OGREDIGEODataSource* poDS;

    OGRFeatureDefn*    poFeatureDefn;
    OGRSpatialReference *poSRS;

    int                nNextFID;

    OGRFeature *       GetNextRawFeature();

    std::vector<OGRFeature*> aosFeatures;

    /* Map attribute RID ('TEX2_id') to its index in the OGRFeatureDefn */
    std::map<CPLString, int> mapAttributeToIndex;

  public:
                        OGREDIGEOLayer(OGREDIGEODataSource* poDS,
                                       const char* pszName, OGRwkbGeometryType eType,
                                       OGRSpatialReference* poSRS);
                        virtual ~OGREDIGEOLayer();

    virtual void                ResetReading() override;
    DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(OGREDIGEOLayer)
    virtual OGRFeature *        GetFeature(GIntBig nFID) override;
    virtual GIntBig             GetFeatureCount( int bForce ) override;

    virtual OGRFeatureDefn *    GetLayerDefn() override { return poFeatureDefn; }

    virtual int                 TestCapability( const char * ) override;

    virtual OGRErr              GetExtent(OGREnvelope *psExtent, int bForce) override;
    virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override
                { return OGRLayer::GetExtent(iGeomField, psExtent, bForce); }

    void                        AddFeature(OGRFeature* poFeature);

    int                         GetAttributeIndex(const CPLString& osRID);
    void                        AddFieldDefn(const CPLString& osName, OGRFieldType eType,
                                             const CPLString& osRID);
};

/************************************************************************/
/*                         OGREDIGEODataSource                          */
/************************************************************************/

typedef std::pair<int, int> intintType;
typedef std::pair<double, double> xyPairType;
typedef std::vector< xyPairType > xyPairListType;
typedef std::pair<CPLString, CPLString> strstrType;
typedef std::vector<CPLString> strListType;

/* From the .DIC file */
class OGREDIGEOAttributeDef
{
    public:
        OGREDIGEOAttributeDef() {}

        CPLString osLAB; /* e.g. TEX2 */
        CPLString osTYP; /* e.g. T */
};

/* From the .SCD file */
class OGREDIGEOObjectDescriptor
{
    public:
        OGREDIGEOObjectDescriptor() {}

        CPLString osRID;        /* e.g. BATIMENT_id */
        CPLString osNameRID;    /* e.g. ID_N_OBJ_E_2_1_0 */
        CPLString osKND;        /* e.g. ARE */
        strListType aosAttrRID; /* e.g. DUR_id, TEX_id */
};

/* From the .SCD file */
class OGREDIGEOAttributeDescriptor
{
    public:
        OGREDIGEOAttributeDescriptor() : nWidth(0) {}

        CPLString osRID;        /* e.g. TEX2_id */
        CPLString osNameRID;    /* e.g. ID_N_ATT_TEX2 */
        int nWidth;             /* e.g. 80 */
};

/* From the .VEC files */
class OGREDIGEOFEADesc
{
    public:
        OGREDIGEOFEADesc() {}

        std::vector< strstrType > aosAttIdVal; /* e.g. (TEX2_id,BECHEREL),(IDU_id,022) */
        CPLString osSCP;                       /* e.g. COMMUNE_id */
        CPLString osQUP_RID;                   /* e.g. Actualite_Objet_X */
};

class OGREDIGEODataSource final: public OGRDataSource
{
    friend class OGREDIGEOLayer;

    char*               pszName;
    VSILFILE*           fpTHF;

    OGRLayer**          papoLayers;
    int                 nLayers;

    VSILFILE*           OpenFile(const char *pszType,
                                 const CPLString& osExt);

    // TODO: Translate comments to English.
    CPLString osLON; /* Nom du lot */
    CPLString osGNN; /* Nom du sous-ensemble de données générales */
    CPLString osGON; /* Nom du sous-ensemble de la référence de coordonnées */
    CPLString osQAN; /* Nom du sous-ensemble de qualité */
    CPLString osDIN; /* Nom du sous-ensemble de définition de la nomenclature */
    CPLString osSCN; /* Nom du sous-ensemble de définition du SCD */
    strListType aosGDN; /* Nom du sous-ensemble de données géographiques */
    int                 ReadTHF(VSILFILE* fp);

    CPLString           osREL;
    OGRSpatialReference* poSRS;
    int                 ReadGEO();

    /* Map from ID_N_OBJ_E_2_1_0 to OBJ_E_2_1_0 */
    std::map<CPLString,CPLString> mapObjects;

    /* Map from ID_N_ATT_TEX2 to (osLAB=TEX2, osTYP=T) */
    std::map<CPLString,OGREDIGEOAttributeDef> mapAttributes;
    int                 ReadDIC();

    std::vector<OGREDIGEOObjectDescriptor> aoObjList;
    /* Map from TEX2_id to (osNameRID=ID_N_ATT_TEX2, nWidth=80) */
    std::map<CPLString,OGREDIGEOAttributeDescriptor> mapAttributesSCD;
    int                 ReadSCD();

    int                 bExtentValid;
    double              dfMinX;
    double              dfMinY;
    double              dfMaxX;
    double              dfMaxY;
    int                 ReadGEN();

    /* Map from Actualite_Objet_X to (creationData, updateData) */
    std::map<CPLString,intintType> mapQAL;
    int                 ReadQAL();

    std::map<CPLString, OGREDIGEOLayer*> mapLayer;

    int                 CreateLayerFromObjectDesc(const OGREDIGEOObjectDescriptor& objDesc);

    std::map< CPLString, xyPairType >                 mapPNO; /* Map Noeud_X to (x,y) */
    std::map< CPLString, xyPairListType >             mapPAR; /* Map Arc_X to ((x1,y1),...(xn,yn)) */
    std::map< CPLString, OGREDIGEOFEADesc >           mapFEA; /* Map Object_X to FEADesc */
    std::map< CPLString, strListType >                mapPFE_PAR; /* Map Face_X to (Arc_X1,..Arc_Xn) */
    std::vector< std::pair<CPLString, strListType > > listFEA_PFE; /* List of (Object_X,(Face_Y1,..Face_Yn)) */
    std::vector< std::pair<CPLString, strListType > > listFEA_PAR; /* List of (Object_X,(Arc_Y1,..Arc_Yn))) */
    std::vector< strstrType >                         listFEA_PNO; /* List of (Object_X,Noeud_Y) */
    std::map< CPLString, CPLString>                   mapFEA_FEA; /* Map Attribut_TEX{X}_id_Objet_{Y} to Objet_Y */

    int                 bRecodeToUTF8;
    int                 bHasUTF8ContentOnly;

    int                 ReadVEC(const char* pszVECName);

    OGRFeature*         CreateFeature(const CPLString& osFEA);
    int                 BuildPoints();
    int                 BuildLineStrings();
    int                 BuildPolygon(const CPLString& osFEA,
                                     const strListType& aosPFE);
    int                 BuildPolygons();

    int                 iATR, iDI3, iDI4, iHEI, iFON;
    int                 iATR_VAL, iANGLE, iSIZE, iOBJ_LNK, iOBJ_LNK_LAYER;
    double              dfSizeFactor;
    int                 bIncludeFontFamily;
    int                 SetStyle(const CPLString& osFEA,
                                 OGRFeature* poFeature);

    std::set< CPLString >  setLayersWithLabels;
    void                CreateLabelLayers();

    int                 bHasReadEDIGEO;
    void                ReadEDIGEO();

  public:
                        OGREDIGEODataSource();
                        virtual ~OGREDIGEODataSource();

    int                 Open( const char * pszFilename );

    virtual const char*         GetName() override { return pszName; }

    virtual int                 GetLayerCount() override;
    virtual OGRLayer*           GetLayer( int ) override;

    virtual int                 TestCapability( const char * ) override;

    int                         HasUTF8ContentOnly() { return bHasUTF8ContentOnly; }
};

#endif /* ndef OGR_EDIGEO_H_INCLUDED */
