#ifndef __TRAFFIC_LIGHT_H__
#define __TRAFFIC_LIGHT_H__

#include <memory>
#include <algorithm>
#include <cstdlib>
#include <sstream>
#include <cfloat>
#include <list>
#include <atomic>
#include <map>
#include <array>
#include <thread>
#include <chrono>
#include <iostream>
#include <vector>
#include <string.h>
#include "traffic_info.h"
#include "car.h"
#include <string>
#include "geo_hash.h" 
#include "structdef.h"
#include "classdef.h"
NAMESPACE_POINT_BEGIN(NAMESPACE_POINT)
//#define MAX_SCOPE_BIGCAR  300//像素
#define MID_CAR_LENGTH_GROUP 5//像素
#define RUN_LIGHT_DIS 20//闯红灯与绿灯的距离
//路口红绿灯
//大巷红绿灯

//路口规则
//小车避让大车规则
//代理模式
//装饰器模式
//抽象工厂模式

//x->大        speed 正
//x->恒  
//      y->大  speed 正 
//      y->小  speed 负
//x->小        speed 负

//这里的初始化红绿灯组vector初始化，因数据库配置和实际情况进行初始化，不能保证通用，需要在不同的情形下特殊处理
//这里是根据区域划分红绿灯，然后根据红绿灯位置按照（上行或者下行）进行排序
//这里初始化根据，每一条巷道为一组，遇到拐点，则是新的巷道。因为，拐点必有红绿灯。
//需要考虑到T字口和十字口中有车辆过来，但非是指定区域即辅运大巷
struct Manage
{
    geo_list m_g;
    std::map<std::string,std::shared_ptr<card_interface>> m_map;
    std::shared_ptr<card_interface> operator [](std::string cardid)
    {
        return m_map[cardid];
    }
    const std::shared_ptr<card_interface> operator [](std::string cardid) const
    {
        auto iter = m_map.find(cardid);
        if(iter == m_map.end())
          return nullptr;
        else
          return iter->second;
    }
};
//初始化红绿灯组，根据区域进行划分
struct InitData
{
    void read_dat_group(const char * fname);
    void read_dat_light(const char * fname);
    std::map<int,std::shared_ptr<TrafficLightGroup>> m_Map;
    void showInfo()
    {
        std::cout << "-------xxxxxxxxxxxxxxxxxxx------------------------\n";
        for(const auto x : m_Map)
          std::cout << x.second->showinfo()<<std::endl;
    }
};

class DecoratorRule;
class Rule
{
public:
    Rule()
    {}
    void setPtr(std::shared_ptr<DecoratorRule> p)
    {
        m_owner = p;
    }
    virtual std::vector<std::shared_ptr<TrafficLightGroup>> handleRule(std::shared_ptr<card_interface> c= 0)  = 0;
	virtual std::shared_ptr<RunRedLight> check_run_red_light(std::shared_ptr<card_interface> c ,double dis){return nullptr;}
    virtual void put(std::shared_ptr<TrafficLightGroup> tlp) = 0;
    virtual void put(std::vector<std::shared_ptr<TrafficLightGroup>> && vec) = 0;
    virtual std::string showInfo() = 0;
	virtual std::vector<std::string> find_near(int x,int y,int dist,const std::string & card_no);

	std::string itostr(int gid)
    {
        char buf[10];
        sprintf(buf,"%d",gid);
        std::string str(buf);
        return std::move(str);
    }
    bool sortCar(const std::string &c1,const std::string &c2,std::shared_ptr<TrafficLightGroup> tlp_ptr)
    {
        auto card1 = getCard(c1);
        auto card2 = getCard(c2);
        double d1=DBL_MAX, d2 = DBL_MAX;
        if(card2 != nullptr)
        {
            d2 = tlp_ptr->dist(card2->getX(),card2->getY());
        }
        if(card1 != nullptr)
        {
            d1 = tlp_ptr->dist(card1->getX(),card1->getY());
        }
        return d1 < d2;
    }
	// 在红绿灯组数组m_pTrafficLight中找离位置点（x,y)最近的灯组m_specialFlag、m_line、m_directDist以及m_id（灯组ID）信息
    std::tuple<bool,line,double,int> findNearLightInfo(double x,double y,std::shared_ptr<TrafficLightGroup> tlg_ptr)
    {
        int lightId = 0; 
        double max = DBL_MAX;
        bool special = false; 
        line l;
        double distDirect = 0;
        for(const auto px : tlg_ptr->m_pTrafficLight)
        {
            double tmp = px->dist(x,y);
            if(max > tmp)
            {
                max = tmp;
                special = px->m_specialFlag?true:false;
                l = px->m_line;
                distDirect = px->m_directDist;
                lightId= px->m_id;
            }
        }
        return std::make_tuple(special,l,distDirect,lightId);

    }
    std::shared_ptr<card_interface> getCard(const std::string &card_no);
    virtual ~Rule() {}
    std::weak_ptr<DecoratorRule> m_owner;
};

class CrossingRule:public Rule
{
public:
    CrossingRule()
    {}
    virtual void setPtr(std::shared_ptr<DecoratorRule> p)
    {
        m_owner = p;
    }
    //谁先到达路口红绿灯指定的距离，which side turn green.then else turn red..
    virtual bool getBigCarFlag(const std::string &card_no);
   //here should another thread to handle it .
    bool  handleManualControl(std::shared_ptr<TrafficLightGroup> pt);
    bool findNearLight(const std::string & card_no,std::shared_ptr<TrafficLightGroup> tlg_ptr,bool  a = false);
    bool handleSpecialAvondance(std::shared_ptr<TrafficLightGroup> pt);
    bool  handleCrossing(std::shared_ptr<TrafficLightGroup> pt) ;
    virtual std::vector<std::shared_ptr<TrafficLightGroup>> handleRule(std::shared_ptr<card_interface> c=nullptr);
    void changeCarState(std::string & card_no,std::shared_ptr<TrafficLightGroup> tlg_ptr);
    void put(std::shared_ptr<TrafficLightGroup> tlp)
    {
        m_CTrafficLightGroupMap.push_back(tlp);
       // std::cout << tlp->showinfo()<<std::endl;
    }
    void put(std::vector<std::shared_ptr<TrafficLightGroup>> && vec)
    {
        m_CTrafficLightGroupMap = vec; 
       // std::cout << "+++++++++++\n";
       // for(const auto x : m_CTrafficLightGroupMap)
       //   std::cout << x->showinfo()<<std::endl;
    }

    virtual std::string showInfo()
    {
        std::stringstream ss;
        ss<<"CrossingRule:{{";
        for(const auto px : m_CTrafficLightGroupMap)
        {
            ss<<"gId:"<<px->m_gId<<",X:"<<px->x<<"Y:"<<px->y;
            for(const auto py : px->m_pTrafficLight)
              ss<<"[lId:"<<py->m_id<<",x:"<<py->x<<",y:"<<py->y<<"],";
            ss<<"},{";
        }
        ss<<"}}";
        return std::move(ss.str());
    }
public:
    std::vector<std::shared_ptr<TrafficLightGroup>> m_CTrafficLightGroupMap;
};
class AvoidanceRule:public Rule
{
public:
    AvoidanceRule()
    {}
    virtual std::vector<std::shared_ptr<TrafficLightGroup>> handleRule(std::shared_ptr<card_interface> c=nullptr);
	virtual std::shared_ptr<RunRedLight> check_run_red_light(std::shared_ptr<card_interface> c,double reddis);
	void add_one(std::shared_ptr<TrafficLightGroup> & pt,std::shared_ptr<card_interface> &c,std::vector<std::shared_ptr<TrafficLightGroup>> &vt,LIGHT_COLOUR lc,LIGHT_COLOUR lc_);
    void changeGroup(std::shared_ptr<TrafficLightGroup> &p,point pt,LIGHT_COLOUR lc,LIGHT_COLOUR lc_);
    void eraseTwoGroup(std::shared_ptr<card_interface> &c,std::vector<std::shared_ptr<TrafficLightGroup>> &vt);
    void  eraseTrafficLightGroup(bool a,std::shared_ptr<card_interface> &c,std::vector<std::shared_ptr<TrafficLightGroup>> &vt);
    std::vector<std::shared_ptr<TrafficLightGroup>> findGroup(double x,double y,int areaid,double vv, std::shared_ptr<card_interface> c);
    bool getMidCar(std::shared_ptr<card_interface> bigcar,std::shared_ptr<TrafficLightGroup> & one,std::shared_ptr<TrafficLightGroup> & two);
	bool Diff(std::shared_ptr<TrafficLightGroup> &p,point pt,LIGHT_COLOUR lc,LIGHT_COLOUR lc_);
//后续小车避让大车规则，只需要找到前方的两个红绿灯，找到两个对比一下之前的记录，如果灯组改变了，则修改，如果没变，则判断是否有小车，进行改变
//如果只找到一个红绿灯，查看是否含有记录，如果有，则不坐任何处理。
    bool  findTwoLightGroupMidCar(std::shared_ptr<TrafficLightGroup> one,std::shared_ptr<TrafficLightGroup>two,std::shared_ptr<card_interface> bigcar,std::shared_ptr<card_interface> car) ;
    void put(std::shared_ptr<TrafficLightGroup> tlp)
    {
        m_CTrafficLightGroupMap[tlp->m_areaId].push_back(tlp);
       // std::cout << tlp->showinfo()<<std::endl;
    }
    void put(std::vector<std::shared_ptr<TrafficLightGroup>> && vec)
    {
        for(const auto x : vec)
        {
            m_CTrafficLightGroupMap[x->m_areaId].push_back(x);
          //  std::cout << "=+++++++++++=\n";
           // std::cout << x->showinfo()<<std::endl;
        }
    }
    void sort()
    {
		TRACE(_T("size: %d"),m_CTrafficLightGroupMap.size());
        for(auto & x:m_CTrafficLightGroupMap)
        {
            if(x.second.size()<=1)
              continue;
            line l(**x.second.begin(),**std::prev(x.second.end()));
            for(const auto & y :m_CTrafficLightGroupMap)
            {
                if(x.first == y.first)
                  continue;
                for(const auto & t:y.second)
                {
                    if(l.contain(*t,0.001))
                    {
                        if(t->m_areaId != x.first)
                            x.second.push_back(t);
                    }
                }
            }
        }
        for(auto &x : m_CTrafficLightGroupMap)
        {
            std::sort(x.second.begin(),x.second.end(),[](std::shared_ptr<TrafficLightGroup> one ,std::shared_ptr<TrafficLightGroup> two )->bool{return *one < *two;});
            x.second.erase(std::unique(x.second.begin(),x.second.end(),[](std::shared_ptr<TrafficLightGroup> one ,std::shared_ptr<TrafficLightGroup> two )->bool{return *one == *two;}),x.second.end());
        }
//      auto x = findGroup(4727,-100,6,-10);
//      for(auto c : x)
//      {
//          if(c!=nullptr)
//            std::cout << "4444444444444444444444444444444444------"<<c->m_gId<<" "<<c->x<<" "<<c->y<<std::endl;
//      }
//      x = findGroup(4627,-75,2,-10);
//      for(auto c : x)
//      {
//          if(c!=nullptr)
//            std::cout << "4444444444444444444444444444444444------"<<c->m_gId<<" "<<c->x<<" "<<c->y<<std::endl;
//      }
#if 0
        //here should use reference........
        for(auto &x : m_CTrafficLightGroupMap)
            std::sort(x.second.begin(),x.second.end(),[](std::shared_ptr<TrafficLightGroup> one ,std::shared_ptr<TrafficLightGroup> two )->bool{return *one < *two;});

        std::map<int,std::tuple<double,double,double>> vtm;
        for(auto &x : m_CTrafficLightGroupMap)
        {
            if(x.second.size()<=1)
              continue;
            //line l(**x.second.begin(),**x.second.end());
            auto abc = (*x.second.begin())->get_abc(**std::prev(x.second.end()));
            for(const auto y : vtm)
            {
              if(std::get<0>(abc)==std::get<0>(y.second)&&std::get<1>(abc)==std::get<1>(y.second)&&std::get<2>(abc)==std::get<2>(y.second))
              {
                  //should initialization with size when Using std::merge
                  std::vector<std::shared_ptr<TrafficLightGroup>>  vt(m_CTrafficLightGroupMap[y.first].size()+x.second.size());
                  for(const auto c:m_CTrafficLightGroupMap[y.first])
                    std::cout << c->x<<"---===0---="<<c->y<<std::endl;
                  for(const auto c:x.second)
                    std::cout << c->x<<"---===0---="<<c->y<<std::endl;
                  std::merge(m_CTrafficLightGroupMap[y.first].begin(),m_CTrafficLightGroupMap[y.first].end(),x.second.begin(),x.second.end(),std::begin(vt),[](std::shared_ptr<TrafficLightGroup> one ,std::shared_ptr<TrafficLightGroup> two )->bool{return *one < *two;});
                  x.second = vt;
                  m_CTrafficLightGroupMap[y.first] = vt;
              }
            }

            vtm.insert({x.first,abc});
        }
#endif
    }
    virtual std::string showInfo()
    {
        //should sort first..
        //sort();
        std::stringstream ss;
        ss<<"AvoidanceRule:{{{";
        for(const auto p : m_CTrafficLightGroupMap)
        {
            for(const auto px : p.second)
            {
                ss<<"AreaId:{"<<p.first<<"}gId:"<<px->m_gId<<",AreaId:"<<px->m_areaId<<",X:"<<px->x<<"Y:"<<px->y;
                for(const auto py : px->m_pTrafficLight)
                    ss<<"[lId:"<<py->m_id<<",x:"<<py->x<<",y:"<<py->y<<"],";
               ss<<"},{" ;
            }
            ss<<"},#------------------#{";
        }
        ss<<"}}";
        return std::move(ss.str());
    }
public:
    std::map<int,std::vector<std::shared_ptr<TrafficLightGroup>>> m_CTrafficLightGroupMap;
};
class CarManager;
class DecoratorRule:public std::enable_shared_from_this<DecoratorRule>
{
public:
    DecoratorRule(CarManager* m)
        :m_(m)
    {

    }
    std::string showInfo()
    {
        return m_rule->showInfo();
    }
    void put(std::shared_ptr<TrafficLightGroup> tlp)
    {
        m_rule->put(tlp);
    }
    void put(std::vector<std::shared_ptr<TrafficLightGroup>> && vec)
    {
        m_rule->put(std::move(vec));
    }
    virtual void handleRule(std::shared_ptr<card_interface> c = nullptr){}
	virtual std::shared_ptr<RunRedLight> check_run_red_light(std::shared_ptr<card_interface> c ,double dis){return nullptr;}
    virtual  std::shared_ptr<DecoratorRule> getPtr() = 0;
    virtual void CreateRule() = 0;
    std::vector<std::string> find_near(double x,double y,double dist,std::string cardid);
    std::shared_ptr<card_interface> getCard(const std::string &card_no);
    virtual ~DecoratorRule(){}

    std::shared_ptr<Rule> m_rule;
    //std::shared_ptr<Manage> m_;
	CarManager *m_;
};
class Uncopyable
{
protected:
	Uncopyable(){}
	~Uncopyable(){}
private:
	Uncopyable(const Uncopyable & lhs);
	Uncopyable & operator=(const Uncopyable &lhs);
};
class DecoratorRuleCrossing:public DecoratorRule,private Uncopyable
{
public:
   // DecoratorRuleCrossing(const DecoratorRuleCrossing &) = delete;
   // DecoratorRuleCrossing & operator=(const DecoratorRuleCrossing &) =delete;

    std::shared_ptr<DecoratorRule> getPtr()
    {
        return shared_from_this();
    }
    DecoratorRuleCrossing(CarManager* m)
        :DecoratorRule(m)
         ,b_exit(false)
    {
        m_pthread = NULL;
    }

    virtual void CreateRule()
    {
        m_rule = std::make_shared<CrossingRule>();
        m_rule->setPtr(getPtr());
    }
    void run();
    void handleRule(std::shared_ptr<card_interface> c = nullptr)
    {
        m_pthread = new std::thread(&DecoratorRuleCrossing::run,this);
    }
    
    ~DecoratorRuleCrossing()
    {
        b_exit = true;
        if(m_pthread!=NULL)
        {
            m_pthread->join();
            delete m_pthread;
        }
    }
private:
    std::thread * m_pthread;
    bool b_exit;
};

class DecoratorRuleAvoidance:public DecoratorRule
{
public:
    DecoratorRuleAvoidance(CarManager* m)
        :DecoratorRule(m)
    {

    }
    std::shared_ptr<DecoratorRule> getPtr()
    {
        return shared_from_this();
    }
    
    virtual void CreateRule()
    {
        m_rule = std::make_shared<AvoidanceRule>();
        m_rule->setPtr(getPtr());
    }
    void handleRule(std::shared_ptr<card_interface> c = nullptr);
	virtual std::shared_ptr<RunRedLight> check_run_red_light(std::shared_ptr<card_interface> c,double dis);
private:
};
/*
static int str_split(char*s,char**rc)
{
	char**o=rc;

	for(;*s;)
	{
		*o=strtok_r(s,",",&s);
		o++;
	}

	return o-rc;
}


int main()
{
    Manage m;
    //test point func
    TrafficLightGroup *ctlg = new TrafficLightGroup(1,1,0,12,12.5,5,10,90) ; 
    std::cout <<"direct:"<< ctlg->dist_direct(3,1)<<std::endl;;
    delete ctlg;    

    //test self-thread.
    //std::shared_ptr<Rule>  r =std::make_shared<CrossingRule> ();
    DecoratorRule* drc = new DecoratorRuleCrossing(&m);
    drc->CreateRule();
    drc->handleRule();
    delete drc;
    //test line 
    line l(point(100,10),point(120,10));
    std::cout << l.dist(point(130,10))<<std::endl;
    line ll(point(4727,75),point(4727,88));
    std::cout << ll.a<<' '<<ll.b<<' '<<ll.c<<"=illlll"<<std::endl; 
    auto abc = point(4727,75).get_abc(point(4727,88));
    std::cout << std::get<0>(abc)<<' '<<std::get<1>(abc)<<' '<<std::get<2>(abc)<<std::endl;
    line lll(point(4729,75),point(4729,88));
    std::cout << lll.a<<' '<<lll.b<<' '<<lll.c<<"=iixxlllll"<<std::endl; 

    //read config
    InitData Id;
    Id.read_dat_group("dat_group.txt");
    Id.read_dat_light("dat_light.txt");
    Id.showInfo();
    //get map for trafficLightGroups includes TrafficLights
    //std::shared_ptr<Rule> CrossingR = std::make_shared<CrossingRule>(m);
    //CrossingR->put(std::move(Id.m_CrossingMap));
    //std::shared_ptr<Rule> AvoidanceR = std::make_shared<AvoidanceRule>(m);

    uint64_t tt = time(NULL)*1000;
    std::shared_ptr<card_interface> bc24 = std::make_shared<c>("2:4",tt,4470,75,false,1.1,2);//cardid timet x y bigcar speed,areaid
    std::shared_ptr<card_interface> bc22 = std::make_shared<c>("2:2",tt,4650,75,false,-1.1,2);//cardid timet x y bigcar speed.areaid

    m.m_map.insert({"2:4",bc24});
    m.m_map.insert({"2:2",bc22});
//  CrossingR->update(4470,-75,"2:4");
//  这里需要把y转化成-
    m.m_g.update(4650,-75,"2:2");
    //auto av = AvoidanceR->find_near(4600,-75,100,"2:4");
    std::shared_ptr<DecoratorRule> DecCrossingRule = std::make_shared<DecoratorRuleCrossing>(&m);
    std::shared_ptr<DecoratorRule> DecAvoidanceRule = std::make_shared<DecoratorRuleAvoidance>(&m);

    for(const auto px : Id.m_Map)
    {
        //if(px.second->m_gId == 1)
         // px.second->store(2);
//        if(px.second->m_gId == 5)
//          bc24->push_back(px.second);
//        if(px.second->m_gId == 6)
//        {
//          bc24->push_back(px.second);
//          px.second->store(3);
//        }
        DecAvoidanceRule->put(px.second);
        DecCrossingRule->put(px.second);
    }
    //DectoratorRule  do next..
//    DecCrossingRule->handleRule();
    //DecAvoidanceRule->handleRule();

#if 0 
    //test the  sort for TrafficLightGroup............
    std::shared_ptr<TrafficLightGroup> p = std::make_shared<CrossingTrafficLightGroup>(1,2,0,12,12.5,5,10);
    std::shared_ptr<TrafficLightGroup> p1 = std::make_shared<AvoidanceTrafficLightGroup>(2,2,0,12,5,10);
    std::shared_ptr<TrafficLightGroup> p2 = std::make_shared<CrossingTrafficLightGroup>(3,2,0,12,12.5,5,10);
    std::vector<std::shared_ptr<TrafficLightGroup>> vp;
    vp.push_back(p);
    vp.push_back(p2);
    vp.push_back(p1);
    for(auto px:vp)
      std::cout << px->x<<"beforefdfdfd" << px->y<<std::endl;
    std::sort(vp.begin(),vp.end(),[](std::shared_ptr<TrafficLightGroup> one,std::shared_ptr<TrafficLightGroup> two)->bool{std::cout << two->x<<std::endl;return *one<*two;});
    for(auto px:vp)
      std::cout << px->x<<"fdfdfd" << px->y<<std::endl;
#endif  
    
    DecAvoidanceRule->handleRule(bc24);
    std::dynamic_pointer_cast<c>(bc24)->x_ = 4600;     
    std::cout <<"------------------------------------"<<std::endl;
    DecAvoidanceRule->handleRule(bc24);


    std::cout<<"******************************************************************************888"<<std::endl;
    std::cout << CrossingR->showInfo()<<std::endl;;
    std::cout<<"************************888"<<std::endl;
    std::cout << AvoidanceR->showInfo()<<std::endl;;
    std::cout<<"**********************************************888"<<std::endl;
    return 0;
}
*/
NAMESPACE_POINT_END(NAMESPACE_POINT)
#endif