#include "event.h"
#include "area.h"
#include "card_base.h"
#include "common_tool.h"
#include "log.h"

#include "area_business_count_checker.h"
/*
	判断当前区域a中的人数是否超过设定人数,超过后告警
	区域内实时人数存储在area对象中,在当前类on_enter/on_leave中进行更新
	整个井下的超员和某个区域的超员都使用这个代码
*/

static void check_event(bool &event_flag,EVENT_TYPE et,EVENT_DIS_TYPE edt,int id)
{
    if(!event_flag)
    {
        auto ev_p = event_list::instance()->get_event_area(id,et,edt);
        if (ev_p && !ev_p->is_end())
            event_flag = true;
    }
}

//服务器重启加载数据
void area_business_count_checker::on_load_his(const std::shared_ptr<area_hover>&a,const std::shared_ptr<card_location_base>&c,std::shared_ptr<business_data>&ptr)
{
    if (nullptr == a->m_area )
        return ;
    if (c->is_person())
    {
        EVENT_TYPE ev = a->m_area->is_mine()?EVENT_TYPE::ET_OVER_COUNT_PERSON : EVENT_TYPE::ET_AREA_OVER_COUNT_PERSON ;
        check_event(a->m_area->m_event_person_count,ev,DT_NORMAL,a->m_area->id());
        check_event(a->m_area->m_event_person_show_count,ev,DT_SPECIAL,a->m_area->id());
    }
    else if (c->is_vehicle())
    {
        EVENT_TYPE ev = a->m_area->is_mine()?EVENT_TYPE::ET_OVER_COUNT_VEHICLE : EVENT_TYPE::ET_AREA_OVER_COUNT_VEHICLE ;
        check_event(a->m_area->m_event_vehicle_count,ev,DT_NORMAL,a->m_area->id());
        check_event(a->m_area->m_event_vehicle_show_count,ev,DT_SPECIAL,a->m_area->id());
    }
    on_enter(a,c,ptr);
}
//增加计数,并进行判断
//多线程环境有可能同时产生相同的告警。
//如果多个线程同一时间触发。
void area_business_count_checker::on_enter(const std::shared_ptr<area_hover>&a,
                                           const std::shared_ptr<card_location_base>&c,std::shared_ptr<business_data>&ptr)
{
	if (nullptr == a->m_area )
		return ;
	if (c->is_person())
	{
        int limit_val=a->m_area->m_limit_person_count;
        int aid=a->m_area->id();
        if(limit_val<=0)
        {
            log_warn("on_enter_area_id:%d,limit_person_count is 0.so should not run area_business_count_checker...",aid);
            return;
        }
        if(!ptr)
		    a->m_area->m_person_count ++;
        if(c->m_display)
		    a->m_area->m_person_show_count ++ ;

        _add_person_count_event(a,limit_val,"person_count_enter");
	}
	else if (c->is_vehicle())
	{
        int limit_val=a->m_area->m_limit_vehicle_count;
        int aid=a->m_area->id();
        if(limit_val<=0)
        {
            log_warn("on_enter_area_id:%d,limit_vehicle_count is 0.so should not run area_business_count_checker...",aid);
            return;
        }
        if(!ptr)
		    a->m_area->m_vehicle_count ++ ;
        if(c->m_display)
		    a->m_area->m_vehicle_show_count ++ ;

        _add_vehicle_count_event(a,limit_val);
	}
    c->update_display();
}
void area_business_count_checker::on_hover(const std::shared_ptr<area_hover>&a,
                                           const std::shared_ptr<card_location_base>&c,std::shared_ptr<business_data> ptr)
{
    if(!c->eq_display())
    {
        ptr=std::make_shared<business_data>();
        if(c->m_display==1)
          on_enter(a,c,ptr);
        else if(c->m_display==0)
          on_leave(a,c,ptr);
        c->update_display();
        ptr=nullptr;
    }

    if (c->is_person() && a->m_area->get_limit_person_count())
    {
        int limit_val = a->m_area->m_limit_person_count;
        _remove_person_count_event(a,limit_val,"area_business_count_checker::on_hover");
        _add_person_count_event(a,limit_val,"area_business_count_checker::on_hover");
    }
}

//减少计数
void area_business_count_checker::on_leave(const std::shared_ptr<area_hover>&a,
                                           const std::shared_ptr<card_location_base>&c,std::shared_ptr<business_data> ptr)
{
	if (nullptr == a->m_area )return ;
    int flag=c->m_display;
    if(!ptr){
        if(!c->eq_display()){
            c->update_display(); 
            //从0 变成1 之前是0 m_show_count没加1 这里不需要减一
            if(c->m_display==1)flag=0;
            //从1 变成 0 之前是加1了。 这里需要减去
            if(c->m_display==0)flag=1;
        }
    }
	if (c->is_person())
	{
        if(ptr)
		    a->m_area->m_person_show_count -- ;
        else{
		    a->m_area->m_person_count -- ;
            //if(c->m_display)
            if(flag)
		        a->m_area->m_person_show_count -- ;
        }
        _remove_person_count_event(a , a->m_area->m_limit_person_count ,"person_count_leave");
	}
	else if (c->is_vehicle())
	{
        if(ptr)
		    a->m_area->m_vehicle_show_count -- ;
        else{
            a->m_area->m_vehicle_count -- ;
            //if(c->m_display)
            if(flag)
		        a->m_area->m_vehicle_show_count -- ;
        }
        _remove_vehicle_count_event(a,a->m_area->m_limit_vehicle_count);
	}
}

//添加人员告警
void area_business_count_checker::_add_person_count_event(const std::shared_ptr<area_hover>&a
        ,int limit_val,const std::string &desc)
{
    int aid = a->m_area->id();
    int pc = a->m_area->m_person_count.load();
    int pc_ = a->m_area->m_person_show_count.load();
    EVENT_TYPE ev = a->m_area->is_mine() ? EVENT_TYPE::ET_OVER_COUNT_PERSON : EVENT_TYPE::ET_AREA_OVER_COUNT_PERSON;
    if(pc > limit_val )
    {
        lock();
        event_tool::instance()->handle_event(OT_AREA,ev,aid,limit_val,pc,a->m_area->m_event_person_count=true,DT_NORMAL);
        unlock();
        log_info("%s:%d,v_count:%d limit:%d",desc.c_str(),aid,pc,limit_val);
    }
    if(pc_ > limit_val )
    {
        lock();
        event_tool::instance()->handle_event(OT_AREA,ev,aid,limit_val,pc_,a->m_area->m_event_person_show_count=true,DT_SPECIAL);
        unlock();
        log_info("%s:%d,v_count:%d limit:%d",desc.c_str(),aid,pc_,limit_val);
    }
}
//移除人员告警
void area_business_count_checker::_remove_person_count_event(const std::shared_ptr<area_hover>&a
        ,int limit_val,const std::string &desc)
{
    int aid = a->m_area->id();
    int pc = a->m_area->m_person_count.load();
    int pc_ = a->m_area->m_person_show_count.load();
    EVENT_TYPE ev = a->m_area->is_mine() ? EVENT_TYPE::ET_OVER_COUNT_PERSON : EVENT_TYPE::ET_AREA_OVER_COUNT_PERSON;

    if(pc <= limit_val && a->m_area->m_event_person_count)
    {
        lock();
        event_tool::instance()->handle_event(OT_AREA,ev,aid,limit_val,pc,a->m_area->m_event_person_count=false,DT_NORMAL);
        unlock();
        log_info("%s :%d,v_count:%d limit:%d",desc.c_str(),aid,pc,limit_val);
    }
    if(pc_ <= limit_val && a->m_area->m_event_person_show_count)
    {
        lock();
        event_tool::instance()->handle_event(OT_AREA,ev,aid,limit_val,pc_,a->m_area->m_event_person_show_count=false,DT_SPECIAL);
        unlock();
        log_info("%s :%d,v_count:%d limit:%d",desc.c_str(),aid,pc_,limit_val);
    }
}

//添加车数量超出限制告警
void area_business_count_checker::_add_vehicle_count_event(const std::shared_ptr<area_hover>&a
        ,int limit_val,const std::string &desc)
{
    int aid = a->m_area->id();
    int vc=a->m_area->m_vehicle_count.load();
    int vc_=a->m_area->m_vehicle_show_count.load();
    EVENT_TYPE ev = a->m_area->is_mine()?EVENT_TYPE::ET_OVER_COUNT_VEHICLE : EVENT_TYPE::ET_AREA_OVER_COUNT_VEHICLE ;
    if(vc>limit_val){
        lock();
        event_tool::instance()->handle_event(OT_AREA,ev,aid,limit_val,vc,a->m_area->m_event_vehicle_count=true,DT_NORMAL);
        unlock();
        log_info("vehicle_count_enter:%d,v_count:%d limit:%d",aid,vc,limit_val);
    }
    if(vc_>limit_val){
        lock();
        event_tool::instance()->handle_event(OT_AREA,ev,aid,limit_val,vc_,a->m_area->m_event_vehicle_show_count=true,DT_SPECIAL);
        unlock();
        log_info("vehicle_count_enter_show:%d,v_count:%d limit:%d",aid,vc_,limit_val);
    }
}
//移除车数量超出告警
void area_business_count_checker::_remove_vehicle_count_event(const std::shared_ptr<area_hover>&a
        ,int limit_val,const std::string &desc)
{
    int pc=a->m_area->m_vehicle_count.load();
    int pc_=a->m_area->m_vehicle_show_count.load();
    int aid=a->m_area->id();
    EVENT_TYPE ev = a->m_area->is_mine()?EVENT_TYPE::ET_OVER_COUNT_VEHICLE : EVENT_TYPE::ET_AREA_OVER_COUNT_VEHICLE ;
    if(a->m_area->m_event_vehicle_count&& pc <= limit_val){
        lock();
        event_tool::instance()->handle_event(OT_AREA,ev,aid,limit_val,pc,a->m_area->m_event_vehicle_count=false,DT_NORMAL);
        unlock();
        log_info("vehicle_count_leave:%d,v_count:%d limit:%d",aid,pc,limit_val);
    }
    if(a->m_area->m_event_vehicle_show_count&& pc_ <= limit_val){
        lock();
        event_tool::instance()->handle_event(OT_AREA,ev,aid,limit_val,pc_,a->m_area->m_event_vehicle_show_count=false,DT_SPECIAL);
        unlock();
        log_info("vehicle_count_leave_show:%d,v_count:%d limit:%d",aid,pc,limit_val);
    }
}