#ifndef module_traffic_light_rule_h
#define module_traffic_light_rule_h

#include <vector>
#include <list>
#include <map>
#include <unordered_map>
#include <thread>
#include <condition_variable>
#include "module_traffic_light_common.h"
#include "module_traffic_light.h"
#include <boost/circular_buffer.hpp>

using vt_traffic_group = std::vector<traffic_light_group_ptr>;
using mp_traffic_group = std::map<int, vt_traffic_group>;

// 规则基类
struct rule{
    rule(){}
    virtual ~rule(){}

    virtual void handle_rule(pos_data& p) = 0;
    virtual void put(traffic_light_group_ptr tlp) = 0;
    virtual void put(vt_traffic_group&& vc) = 0;
    virtual void put_pos(const pos_data data) = 0;
    // 闯红灯检查
    virtual std::shared_ptr<run_red_light> check_run_red_light(pos_data& p) = 0;
    // 车子按距离红绿灯组坐标点排序
    bool sort_vehicle(const uint64_t lhs, const uint64_t rhs, const traffic_light_group_ptr& g);
    bool sort_vehicle_by_level(const uint64_t lhs, const uint64_t rhs, const traffic_light_group_ptr& g);

    // 在红绿灯组数组中找离位置点(x,y)最近的灯组信息
    traffic_light_ptr find_nearby_light(const point& p, traffic_light_group_ptr g);
};

// 路口规则
struct crossing_rule: rule{
    crossing_rule()
    {
        m_pos.set_capacity(2);
    }
    ~crossing_rule(){}

    // 
    void handle_rule(pos_data& p);
    // 谁先到达炉口红绿灯指定的距离,变绿灯,其他变红灯
    bool get_vehicle_state(const uint64_t& card_id);
    // 自动控制
    bool handle_manual_ctrl(traffic_light_group_ptr g);
    // 查找附近的红绿灯
    bool find_light(const uint64_t& cid, traffic_light_group_ptr g, bool a = false);
    // 避让处理
    bool handle_avoidance(traffic_light_group_ptr g);
    bool avoidance_by_level(traffic_light_group_ptr& group);
    bool avoidance_by_updown(traffic_light_group_ptr& group);
    // 路口处理
    bool handle_crossing(traffic_light_group_ptr group);
    // 修改红绿灯组状态
    void change_state(const uint64_t cid, traffic_light_group_ptr g);
    // 闯红灯
    std::shared_ptr<run_red_light> check_run_red_light(pos_data& p);
    
    void put(traffic_light_group_ptr g)
    {
        m_vt_group.push_back(g);
    }

    void put(vt_traffic_group&& vc)
    {
        m_vt_group = vc;
    }

    void put_pos(const pos_data data)
    {
        m_pos.push_back(data);
    }

    int size()
    {
        return m_vt_group.size();
    }

    private:
        // 灯组
        vt_traffic_group m_vt_group;
        boost::circular_buffer<pos_data> m_pos; 
};

// 避让规则
struct avoidance_rule: rule{
    public:
        avoidance_rule()
        {
            m_pos.set_capacity(2);           
        }
        ~avoidance_rule(){}

        void handle_rule(pos_data& p);
        // 给车卡绑定路口灯组控制,并更改灯组中灯的颜色状态
        void insert(traffic_light_group_ptr g, pos_data& p, vt_traffic_group& vg, const int lc, const int lcr);
        // 改变点p定位附近灯组的状态,满足条件的灯状态改为lc,否改为lcr
        void change_group(const traffic_light_group_ptr& g, const point& p, const int& lc, const int& lcr);
        void change_group(const traffic_light_group_ptr& g, const move_stream& s, const int& lc, const int& lcr);
        // 把车卡从灯组控制中解绑
        void erase(bool a, pos_data& p, vt_traffic_group& vg);
        // 根据车辆与灯组的位置关系,查找灯组
        vt_traffic_group find_group(const pos_data& p);
        vt_traffic_group find_group(const point& po, int aid, double v, const pos_data& p);
        // 两个红绿灯组中间是否有车
        bool get_vehicle(const pos_data& p, vt_traffic_group& vg);
        // 求坐标点与红绿灯组的距离
        bool is_different(traffic_light_group_ptr g, const point& p, const int& lc, const int& lcr);
        // 后续小车避让大车规则,只需要找到前方的两个红绿灯,找到两个对比一下之前的记录,如果灯组改变了,则修改,如果没变,则判断是否有小车,进行改变
        // 如果只找到一个红绿灯,查看是否含有记录,如果有,则不做任何处理
        bool find_vehicle_in_group(vt_traffic_group& vg, std::vector<pos_data>& vv);
        // 闯红灯
        std::shared_ptr<run_red_light> check_run_red_light(pos_data& p);
        // 将灯组放入指定区域内
        void put(traffic_light_group_ptr ptlg)
        {
            m_map_area_group[ptlg->m_area_id].push_back(ptlg);
        }

        void put(vt_traffic_group&& lhs)
        {
            for(const auto x : lhs){
                m_map_area_group[x->m_area_id].push_back(x);
            }
        }

        void put_pos(const pos_data data)
        {
            m_pos.push_back(data);    
        }
    
        int size()
        {
            return m_map_area_group.size();
        }

    private:
        mp_traffic_group m_map_area_group;
        boost::circular_buffer<pos_data> m_pos;
};

using hashmap_light = std::unordered_map<int, traffic_light_ptr>;
using hashmap_group = std::unordered_map<int, traffic_light_group_ptr>;
using map_group = std::map<int, traffic_light_group_ptr>;

#endif