#ifndef __DEF__H__
#define __DEF__H__
#include "point.h"
#include <time.h>
#include "line.h"
#include <ctime>
#include "classdef.h"

NAMESPACE_POINT_BEGIN(NAMESPACE_POINT)
enum Priority
{
    PRI_INIT = 0, 
    PRI_CROSSING= 1, 
    PRI_AVOIDANCE=2,
    PRI_MANUALCONTROL=3
};
//和web对应
enum LIGHT_COLOUR
{
    INIT=0x01,
    RED,
    GREEN,
    SPARK
};
//红绿灯
class TrafficLight :public point
{
public:
    TrafficLight(int32_t id,double x,double y,double z, int32_t readerid,std::string ip,int32_t specialFlag,int32_t port,uint32_t phy_id,uint8_t phy_dir)
        :point(x,y)
         ,m_id(id),z_(z)
         ,readerId_(readerid)
         ,m_ip(ip)
         ,m_specialFlag(specialFlag)
         ,m_directDist(0)
         ,m_state(GREEN)
		 ,m_port(port)
		 ,m_physics_light_id(phy_id)
		 ,m_physics_direction(phy_dir)
		 ,m_rec_time(time(NULL))
		 ,light_state(0)
    {

    }
    void setState(LIGHT_COLOUR lc=GREEN)
    {
        m_state = lc;
    }
	void set(double xx,double yy,std::string ip,int flag,int readerid,int32_t port,uint32_t phy_id,uint8_t phy_dir)
	{
		x = xx;
		y = yy;
		m_ip = ip;
		m_specialFlag =flag;
		readerId_ = readerid;
		m_port = port;
		m_physics_light_id = phy_id;
		m_physics_direction = phy_dir;
	}
	inline int32_t getid(){return m_id;}
	inline LIGHT_COLOUR getState(){return m_state;}
	inline std::string getip(){return m_ip;}
    int32_t m_id;
    double z_;
    int32_t readerId_;
    std::string m_ip;
    int32_t m_specialFlag;
    double m_directDist;
    LIGHT_COLOUR m_state;
	int32_t m_port;
    op::line m_line;

	//add by zhuyf 2018/11/06
	uint32_t m_physics_light_id;		// 物理灯号：红绿灯正反面共享此灯号
	uint8_t m_physics_direction;		// 物理朝向：正面，反面
	uint64_t m_rec_time;				// 红绿灯接收时间
	int light_state;					// 红绿灯状态
	INT64 m_event_list[88]; // 保存事件Id
};

//红绿灯组
class TrafficLightGroup : public point
{
public:
    TrafficLightGroup(double x, double y, double z,int32_t gId,int32_t mapid,int32_t areaid,double scope,int32_t ctime)
        :point(x,y)
         ,m_gId(gId),m_mapId(mapid),m_areaId(areaid)
         ,m_priority(PRI_INIT)
         //,m_ownerFlag(ATOMIC_FLAG_INIT)
         ,m_scope(scope)
         ,m_special(false)
         ,m_controlTime(ctime)
         ,m_timeStamp(0)
		 ,m_used(false)
		 ,m_nLightId(-1)
    {
		m_ownerFlag.clear();
    }
	TrafficLightGroup(double x, double y, double z,int32_t gId,int32_t mapid,int32_t areaid,double scope,int32_t ctime,uint16_t ait)
		:point(x,y)
		,m_gId(gId),m_mapId(mapid),m_areaId(areaid)
		,m_priority(PRI_INIT)
		//,m_ownerFlag(ATOMIC_FLAG_INIT)
		,m_scope(scope)
		,m_special(false)
		,m_controlTime(ctime)
		,m_timeStamp(0)
		,m_auto_control_interval(ait)
		,m_used(false)
	{
		m_ownerFlag.clear();
	}
	std::vector<std::tuple<int,int,int,std::string,int,std::string,int>> getTrafficLightInfo()
	{
		std::vector<std::tuple<int,int,int,std::string,int,std::string,int>>  vt;
		for (const auto x:m_pTrafficLight)
			vt.push_back(std::make_tuple(m_gId,x->getid(),x->getState(),m_ControlName,m_ControlName.empty()?0:1,x->getip(),x->m_port));
		return std::move(vt);
	}
	void set(double xx,double yy,int32_t mapid,int32_t areaid,int32_t ct)
	{
		x = xx;
		y = yy;
		m_mapId = mapid;
		m_areaId = areaid;
		m_controlTime = ct;
	}
	void set(double xx,double yy,int32_t mapid,int32_t areaid,int32_t ct,uint16_t lat)
	{
		x = xx;
		y = yy;
		m_mapId = mapid;
		m_areaId = areaid;
		m_controlTime = ct;
		m_auto_control_interval = lat;
	}
	std::shared_ptr<TrafficLight> get(int32_t lightId)
	{
		for(const auto x:m_pTrafficLight)
			if (x->m_id == lightId)
				return x;
		return nullptr;
	}
    void put(std::shared_ptr<TrafficLight> t)
    {
        t->m_directDist = this->dist_direct(*t);
        std::cout << "Lemon: x:"<<x<<",y:"<<y<<"light x:"<<t->x<<",y:"<<t->y<<",dist:"<<t->m_directDist<<std::endl;
        line l(*this,point(t->x,t->y));
        t->m_line = l;
        m_pTrafficLight.push_back(t);
        if(t->m_specialFlag == 1)
          m_special = true;
    }
    bool getflag(){return m_special;}
    double scope(){return m_scope;}
    std::string showinfo()
    {
        std::stringstream ss;
        ss<<"GID:"<<m_gId<<",gx:"<<x<<",gy:"<<y<<",priority:"<<load()<<",scope="<<m_scope<<" special=" <<(m_special?"true":"false")<<" lights:";
        for(const auto px:m_pTrafficLight)
          ss<<"["<<px->m_id<<","<<px->x<<","<<px->y<<","<<px->m_state<<"]";
        return std::move(ss.str());
    }
    void store(int x)
    {
        m_priority.store(x);
    }
    int load()
    {
        return m_priority.load();
    }
    
	inline void set_status(const bool status)
	{
		m_used.store(status);
	}

	bool get_status()
	{
		return m_used.load();
	}

    bool timeout()
    {
        std::time_t t = time(NULL);
        if(t-m_timeStamp >= m_controlTime)
          return true;
        return false;
    }
	/*
	设置灯组内红绿灯颜色，满足条件的设置为指定灯形状，不满足条件3个面的设为其他相同的灯形状
	*/
    void setLight(int ld,LIGHT_COLOUR lc,LIGHT_COLOUR lc_rever)
    {
        for(auto & px : m_pTrafficLight)
        {
            if(px->m_id == ld)
              px->setState(lc);
            else
              px->setState(lc_rever);
        }
    }
    //手动设置
    void setCrossing(const std::string & cardid,Priority p)
    {
        m_card = cardid;
        store(p);
    }
    void setAvoidance(int ld,LIGHT_COLOUR lc,LIGHT_COLOUR lc_rever)
    {
        m_card.clear();
        m_timeStamp =0;
        store(PRI_AVOIDANCE);
        setLight(ld,lc,lc_rever);
    }
    void setManualControl(const std::string &name,int ld,LIGHT_COLOUR lc)
    {
		getTurn();
        m_ControlName = name;
        m_timeStamp = time(NULL);
        store(PRI_MANUALCONTROL);
        m_card.clear();
        for(auto & px:m_pTrafficLight)
            if(px->m_id == ld)
                px->setState(lc);
		releaseTurn();
    }
	bool Diff(int ld,LIGHT_COLOUR lc,LIGHT_COLOUR lc_rever)
	{
		bool b = false;
		getTurn();
		if (load()<=2)
		{
			for(auto & px : m_pTrafficLight)
			{
				if(px->m_id == ld)
				{
					if (px->getState() != lc)
					{
						b=true;
						break;
					}
				}
				else
				{
					if (px->getState() != lc_rever)
					{
						b=true;
						break;
					}
				}
			}
		}
		if (b)
			//setAvoidance(ld,lc,lc);
			setAvoidance(ld,lc,lc_rever);
		releaseTurn();
		return b;
	}
    void resetGroup()
    {
        store(PRI_INIT);
        m_timeStamp = 0;
        m_ControlName.clear();
        m_card.clear();
		m_sCardId = "";
		set_status(false);
        for(auto &px:m_pTrafficLight)
            px->setState();
    }
    void getTurn()
    {
        while(m_ownerFlag.test_and_set(std::memory_order_acquire));
        //std::cout << "getTurn.."<<m_gId<<std::endl;
    }
    void releaseTurn()
    {
        m_ownerFlag.clear(std::memory_order_release); 
        //std::cout <<"releaseTurn..."<<m_gId<<std::endl;
    }
    std::string getId()const{return m_card;}
    bool noCar(){return m_card.empty();}
    void setId(std::string & id){m_card = id;}
    std::vector<std::shared_ptr<TrafficLight>> m_pTrafficLight; //include ligits
    int32_t m_gId,m_mapId,m_areaId; // group id;
    std::atomic<int> m_priority;//优先级 0 初始值 1 路口控制 2 避让控制 3手动控制
    //int m_priority;
    std::atomic_flag m_ownerFlag;
    double m_scope;
    bool m_special; //
    uint32_t m_controlTime;
    std::time_t m_timeStamp;
    std::string m_ControlName;
    std::string m_card; //如果是优先级1表示小车，2表示大车id
	uint32_t m_auto_control_interval;	//灯组内红绿灯断网情况下自动控制的时间间隔
	std::atomic<bool> m_used;
	int m_nLightId; // 灯组被控制后变绿灯的灯ID
	std::string m_sCardId; // 绑定此灯组的卡号 
    ~TrafficLightGroup()
    {}
};
NAMESPACE_POINT_END(NAMESPACE_POINT)
#endif 
