#ifndef _JFXMAP_SDTYPES_H_
#define _JFXMAP_SDTYPES_H_

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

#include "CoordSys.h"
#include "MapConfig.h"
#include "Serialize.h"
#include "Singleton.h"
#include "World.h"
#include "ajson.hpp"

namespace jf {
typedef uint64_t SdSectionId;

struct SdRadas {
    SdRadas() : curvature(0.0), roll(0.0), pitch(0.0), azimuth(0.0) {}
    SdRadas(double inCurvature, double inRoll, double inPitch, double inAzimuth) : curvature(inCurvature), roll(inRoll), pitch(inPitch), azimuth(inAzimuth) {}
    double curvature = 0;
    double roll = 0;
    double pitch = 0;
    double azimuth = 0;
};

struct BaseNode {
    SdNodeId id;
    double lon = 0;
    double lat = 0;
    double alt = 0;
    int speed_limit_small = 0;
    int speed_limit_big = 0;
    struct Point GetPoint() const;
    // radas r;
};

/**
 * @brief 内存中数据结构
 *
 */
struct SdNode {
    // TODO 这里还没有赋值
    SdNodeId id_p;
    std::vector<SdNodeId> outDegree;  // 对应该点上的出度点
    std::vector<double> outLengths;   // 出度距离
    std::vector<RoadId> outRids;      // 出度rids
    std::vector<SdNodeId> inDegree;   // 对应该点上的入度点
    std::vector<double> inLengths;    // 入度距离
    std::vector<RoadId> inRids;       // 入度rids
    int speed_limit_big;
    int speed_limit_small;
    int level;
    SdRadas radas;
    bool interpolated_node;

    SdNode() : id_p({0, 0, 0}) {}

    bool operator==(const SdNode &other) { return id_p == other.id_p; }
    bool operator!=(const SdNode &other) { return id_p != other.id_p; }

    void GetNexts(std::vector<SdNodeId> &out) const { out = outDegree; }
    void GetPrevs(std::vector<SdNodeId> &out) const { out = inDegree; }
};

inline bool operator<(const SdNode &a, const SdNode &b) { return a.id_p < b.id_p; }

inline bool operator==(const SdNode &a, const SdNode &b) { return a.id_p == b.id_p; }

inline bool operator!=(const SdNode &a, const SdNode &b) { return !(a == b); }

struct BaseWay {
    RoadId id;
    int level;
    std::vector<SdNodeId> nodes;
    int direction = 2;
};

struct BaseBound {
    double minlon;
    double maxlon;
    double minlat;
    double maxlat;
    BaseBound(double inminlon, double inmaxlon, double inminlat, double inmaxlat) {
        minlon = inminlon;
        maxlon = inmaxlon;
        minlat = inminlat;
        maxlat = inmaxlat;
    }
};

struct ShpBound : BaseBound {
    ShpBound(double inminlon = 0, double inmaxlon = 0, double inminlat = 0, double inmaxlat = 0) : BaseBound(inminlon, inminlat, inmaxlon, inmaxlat) {}
};

struct IterPathResult {
    std::vector<IterPathResult> nps;
    std::vector<SdNode> ps;
    void AddNext(SdNode n) { ps.push_back(n); }
    int Size() { return ps.size(); }
};

template <typename InNodeIdType, typename InNodeDataType, typename InSerializeDataType>
class Tile;

template <typename InNodeIdType, typename InNodeDataType, typename TileType>
class World;
class Save;

struct SdSerializeData {
    using saveType = MapConfig::sdConfig;
    Rect2D r;
    std::vector<SdNodeId> m_keys;
    std::vector<SdNode> m_values;
    std::vector<uint64_t> states;
    std::vector<std::vector<SdNodeId>> nodes;
    std::vector<std::vector<Point>> ps;
    SdSerializeData(const Rect2D &inr, const std::map<SdNodeId, SdNode> inm, std::vector<uint64_t> instates, std::vector<std::vector<SdNodeId>> &innodes, std::vector<std::vector<Point>> &inps) : r(inr), states(instates), nodes(innodes), ps(inps) {
        for (auto &iter : inm) {
            auto &k = iter.first;
            auto &v = iter.second;
            m_keys.push_back(k);
            m_values.push_back(v);
        }
    }
    SdSerializeData() : r(Point(0, 0, 0), Point(0, 0, 0)) {}
};

typedef Save SdSave;
typedef Tile<struct SdNodeId, SdNode, SdSerializeData> SdTile;
struct newSdWorld {
    static World<struct SdNodeId, SdNode, SdTile> *Create() { return new World<SdNodeId, SdNode, SdTile>(new SdSave); };
};
typedef Singleton<World<SdNodeId, SdNode, SdTile>, newSdWorld> SdWorld;
}  // namespace jf

#ifndef jfxmap_serialize_override_sdradas
jfxmap_serialize(jf::SdRadas, curvature, roll, pitch, azimuth);
#endif
#ifndef jfxmap_serialize_override_sdNodeId
jfxmap_serialize(jf::SdNodeId, p);
#endif
#ifndef jfxmap_serialize_override_sdNode
jfxmap_serialize(jf::SdNode, id_p, outDegree, outLengths, outRids, inDegree, inLengths, inRids, speed_limit_big, speed_limit_small, level, radas, interpolated_node);
#endif
#ifndef jfxmap_serialize_override_sdSerializeData
jfxmap_serialize(jf::SdSerializeData, m_keys, m_values, r, states, nodes, ps);
#endif

namespace std {
template <>  // function-template-specialization
class hash<jf::SdNodeId> {
   public:
    size_t operator()(const jf::SdNodeId &id) const { return id.p.dLon * 1000000000; }
};

template <>  // function-template-specialization
class hash<jf::SdNode> {
   public:
    size_t operator()(const jf::SdNode &nd) const { return nd.id_p.p.dLon * 1000000000; }
};
}  // namespace std

#endif