#ifndef _JFX_MAPPARSER_H_
#define _JFX_MAPPARSER_H_

#include <iostream>
#include <string>
#include <vector>

#include "HdTypes.h"
#include "SdTypes.h"
//#include "ShpTypes.h"

// using namespace std;

namespace jf {

typedef std::map<SdNodeId, SdNode> MapIdNode;
typedef std::map<RoadId, BaseWay> MapIdWay;
// typedef shared_ptr<MapIdWay> SpMapIdWay;

class MapParser {
   public:
    template <typename boundCallbackType, typename nodeCallbackType, typename wayCallbackType, typename relationCallbackType>
    HdJson Parse(const std::string &file_path, nodeCallbackType nc, wayCallbackType wc, boundCallbackType bc, relationCallbackType rc) {
        MapIdNode mapIdNode = {};
        MapIdWay mapIdWay = {};
        ShpBound stBound = {180, -180, 90, -90};

        // removeMapIdWay(file_path);

        // parse map data
        HdJson json = ParseAll(file_path, mapIdNode, mapIdWay, stBound);

        // update speed limit
        // updateSpeedLimit(file_path, mapIdNode);

        for (auto &node : mapIdNode) {
            nc(node.second);
        }

        for (auto &way : mapIdWay) {
            wc(way.second);
        }

        bc(stBound);

        return json;
    }

   private:
    struct LaneConnection {
        std::vector<HdLaneId> vctNextLaneIds;
        std::vector<HdLaneId> vctPreLaneIds;
    };

   private:
    HdJson ParseAll(const std::string &strPath, MapIdNode &mapOutIdNode, MapIdWay &mapOutIdWay, ShpBound &bdOutBound);

   private:
    void ParseOBJStopLine(const std::string &strPath, std::map<JfDataId, std::vector<ObjStopLine>> &mapOutLinkIdVctStopLine);
    void ParseOBJCrossing(const std::string &strPath, std::map<JfDataId, std::vector<ObjCrossing>> &mapOutLinkIdVctCrossing);
    void ParseOBJTrafficLight(const std::string &strPath, std::map<JfDataId, std::vector<ObjTrafficLight>> &mapOutLinkIdVctTrafficLight, std::map<JfDataId, std::vector<ObjTrafficLight>> &mapOutLaneIdVctTrafficLight);
    void ParseOBJPoint(const std::string &strPath, std::map<JfDataId, std::vector<ObjPoint>> &mapOutLinkIdVctPoint);
    void ParseRoadCrossArea(const std::string &strPath, std::map<JfDataId, std::vector<RoadCrossArea>> &mapOutLinkIdVctCrossArea);
    void ParseJunction(const std::string &strPath, std::map<JfDataId, RoadJunction> &mapOutIdJunction);
    void ParseRoadEdgeNode(const std::string &strPath, std::map<JfDataId, RoadEdgeNode> &mapOutIdEdgeNode);
    void ParseRoadEdgeLink(const std::string &strPath, const std::map<JfDataId, RoadEdgeNode> &mapIdEdgeNode, std::map<JfDataId, RoadEdge> &mapOutIdEdge);
    void ParseRoad(const std::string &strPath, const std::map<JfDataId, std::vector<ObjPole>> mapLinkIdVctPole, const std::map<JfDataId, std::vector<ObjStopLine>> mapLinkIdVctStopLine,
                   const std::map<JfDataId, std::vector<ObjCrossing>> mapLinkIdVctCrossing, const std::map<JfDataId, std::vector<ObjTrafficLight>> mapLinkIdVctTrafficLight, const std::map<JfDataId, std::vector<ObjTrafficSign>> mapLinkIdVctTrafficSign,
                   const std::map<JfDataId, std::vector<ObjOverHead>> mapLinkIdVctOverHead, const std::map<JfDataId, std::vector<ObjFillArea>> mapLinkIdVctFillArea, const std::map<JfDataId, std::vector<ObjBusStop>> mapLinkIdVctBusStop,
                   const std::map<JfDataId, std::vector<ObjHydrant>> mapLinkIdVctHydrant, const std::map<JfDataId, std::vector<ObjParking>> mapLinkIdVctParking, const std::map<JfDataId, std::vector<ObjSpeedBump>> mapLinkIdVctSpeedBump,
                   const std::map<JfDataId, std::vector<ObjNoParking>> mapLinkIdVctNoParking, const std::map<JfDataId, std::vector<RoadCrossArea>> &mapLinkIdVctCrossArea, const std::map<JfDataId, std::vector<ObjPoint>> mapLinkIdVctPoint,
                   const std::map<JfDataId, RoadJunction> &mapIdJunction, const std::map<JfDataId, RoadEdge> &mapIdEdge, std::map<JfDataId, HdLink> &mapOutIdHdLink, ShpBound &bdOutBound);

    void ParseOBJTrafficSign(const std::string &strPath, std::map<JfDataId, std::vector<ObjTrafficSign>> &mapOutLinkIdVctTrafficSign);
    void ParseOBJPole(const std::string &strPath, std::map<JfDataId, std::vector<ObjPole>> &mapOutLinkIdVctPole);
    void ParseOBJText(const std::string &strPath, std::map<JfDataId, std::vector<ObjText>> &mapOutLaneIdVctText);
    void ParseOBJSymbol(const std::string &strPath, std::map<JfDataId, std::vector<ObjSymbol>> &mapOutLaneIdVctSymbol);
    void ParseOBJOverHead(const std::string &strPath, std::map<JfDataId, std::vector<ObjOverHead>> &mapOutLinkIdVctOverHead);
    void ParseOBJNoParking(const std::string &strPath, std::map<JfDataId, std::vector<ObjNoParking>> &mapOutLinkIdVctNoParking);
    void ParseOBJSpeedBump(const std::string &strPath, std::map<JfDataId, std::vector<ObjSpeedBump>> &mapOutLinkIdVctNoParking);
    void ParseOBJParking(const std::string &strPath, std::map<JfDataId, std::vector<ObjParking>> &mapOutLinkIdVctParking);
    void ParseOBJFillArea(const std::string &strPath, std::map<JfDataId, std::vector<ObjFillArea>> &mapOutLinkIdVctFillArea);
    void ParseOBJHydrant(const std::string &strPath, std::map<JfDataId, std::vector<ObjHydrant>> &mapOutLinkIdVctHydrant);
    void ParseOBJBusStop(const std::string &strPath, std::map<JfDataId, std::vector<ObjBusStop>> &mapOutLinkIdVctBusStop);

    void ParseHDLaneNode(const std::string &strPath, std::map<JfDataId, HdLaneNode> &mapOutIdLaneNode);
    void ParseLaneADAS(const std::string &strPath, std::map<JfDataId, std::vector<HdLaneAdas>> &mapOutLaneIdVctLaneAdas);
    void ParseOBJArrow(const std::string &strPath, std::map<JfDataId, std::vector<ObjArrow>> &mapOutLaneIdVctArrow);
    void ParseHDLaneLink(const std::string &strPath, const std::map<JfDataId, HdLaneNode> &mapIdLaneNode, const std::map<JfDataId, std::vector<HdLaneAdas>> &mapLaneIdVctLaneAdas,
                         const std::map<JfDataId, std::vector<ObjArrow>> &mapLaneIdVctArrow,const std::map<JfDataId, std::vector<ObjTrafficLight>> &mapLaneIdVctTrafficLight,
                         const std::map<JfDataId, std::vector<ObjText>> &mapLaneIdVctText, const std::map<JfDataId, std::vector<ObjSymbol>> &mapLaneIdVctSymbol,
                         std::map<JfDataId, HdLink> &mapOutIdHdLink);

    void ParseHDEdgeNode(const std::string &strPath, std::map<JfDataId, HdEdgeNode> &mapOutIdEdgeNode);
    void ParseHDLaneMark(const std::string &strPath, std::map<JfDataId, std::vector<HdLaneMark>> &mapOutEdgeIdVctLaneMark);
    void ParseHDEdgeLink(const std::string &strPath, const std::map<JfDataId, HdEdgeNode> &mapIdEdgeNode, const std::map<JfDataId, std::vector<HdLaneMark>> &mapEdgeIdVctLaneMark, const std::map<JfDataId, HdEdge> &mapIdEdge,
                         std::map<JfDataId, HdLink> &mapOutIdHdLink);

    void MakeSdData(const std::map<JfDataId, HdLink> &mapOutIdHdLink, MapIdNode &mapOutIdNode, MapIdWay &mapOutIdWay);
    void MakeHdLink(const std::map<JfDataId, HdLink> &mapOutIdHdLink, HdJson &jsnOutResult);

    void SortHdEdges(const HdLink &hlLink, std::vector<HdEdge> &vcthlOutEdges);
    void ConvertHdLanes(const HdLink &hlLink, const std::map<HdLaneId, LaneConnection> &cmapLaneIdConnection, std::vector<HdLane> &vcthlOutLanes);
    void ConvertPNLinkIds(const std::map<JfDataId, HdLink> &mapIdHdLink, std::map<HdLinkId, HdLink> &mapIdLink);

    void GetTids(const std::vector<std::vector<double>> &vctvdGeoLink, std::vector<TileId> &vctOutTids);

    // void insertFeatures(const string &strPath, HdJson &data);

    template <typename NumType>
    void AnalyseStrNums(const std::string &strId, std::vector<NumType> &vctNums) {
        if (strId.length() == 0) {
            return;
        }

        std::string flag = ";";
        if (strId.find(flag, 0) != std::string::npos) {
            int position = 0;
            int lastPosition = position;
            // 查找“|”出现的所有位置，并解析
            while ((position = strId.find_first_of(flag, position)) != std::string::npos) {
                std::string id = strId.substr(lastPosition, 10);
                vctNums.push_back(atoll(id.c_str()));
                ++position;
                lastPosition = position;
            }
            std::string id = strId.substr(lastPosition, 10);
            vctNums.push_back(atoll(id.c_str()));
        } else {
            vctNums.push_back(atoll(strId.c_str()));
            return;
        }
    }

    int Factorial(int n);

   private:
    std::string m_strPath;
};

}  // namespace jf

#endif  // _JFX_MAPPARSER_H_