#include "module_call.h"
#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include <vector>
#include <set>
#include <string>
#include <chrono>
#include <algorithm>
#include <area.h>
#include "common_tool.h"
#include "tool_time.h"
#include "ant.h"
#include "websocket/constdef.h"
#include "websocket/wsClientMgr.h"
#include "crc.h"
#include "mine.h"
#include "event.h"

/*
 * @brief   根据卡类型与卡号构造key
 * @param   无
 * @return  返回生成值
 * @note
 * @warning
 * @bug
 * */
uint64_t call_card::to_id64()
{
    return tool_other::type_id_to_u64(cardtype, cardid);
}

/*
 * @brief   根据卡类型与卡号构造卡字符串,形如:0010000001200
 * @param   无
 * @return  返回卡号
 * @note
 * @warning
 * @bug
 * */
std::string call_card::to_id64_str()
{
    return tool_other::type_id_to_str(cardtype, cardid);
}

/*
 * @brief   根据卡类型与卡号构造key
 * @param   无
 * @return  返回生成值
 * @note
 * @warning
 * @bug
 * */
bool call_card::is_timeout()
{
    uint32_t seconds = tool_time::elapse_seconds(call_time);
    return (seconds >= call_time_out*60);
}

bool module_call::call_user::is_timeout()
{
    uint32_t seconds = tool_time::elapse_seconds(call_time);
    return (seconds >= call_time_out*60);
}

void module_call::to_node_element(rapidjson::Value& out_elemet,
                                  const std::shared_ptr<call_card> card_ptr,
                                  rapidjson::Document::AllocatorType& allocator,bool f)
{
    tool_json::push_back(out_elemet, card_ptr->user_name, allocator);
    tool_json::push_back(out_elemet, card_ptr->to_id64_str(), allocator);
    uint32_t sid= card_ptr->stationid;
    if(f)sid=0;

    out_elemet.PushBack(sid, allocator);
    out_elemet.PushBack(tool_time::to_ms(card_ptr->call_time), allocator);

    out_elemet.PushBack(card_ptr->call_type_id, allocator);
    out_elemet.PushBack(card_ptr->call_state, allocator);
}

void module_call::run()
{
    std::vector<call_card_ptr> arr;

    get_all_call_cards(arr);

    if(arr.empty())
    {
        return ;
    }
    //转发给web
    //swsClientMgr.send(JSON_CMD_VALUE_PUSH, to_call_card_list_json(arr));

	// 获得pv_anti_collision告警json
    /*
	std::string ac = get_json_anti_collision();
    if(!ac.empty()){
        log_info("send2web: %s", ac.c_str());
        swsClientMgr.send(JSON_CMD_VALUE_PUSH, ac);
    }
	*/

    //将呼叫命令发送给标识卡终端
    call_site_map site_map;
    get_site_map(arr, site_map);

    if(!site_map.empty())
    {
        send_to_sites(site_map);
    }
}

///发呼叫的报文数据给分站
void module_call::send_to_sites(call_site_map& site_map)
{
    auto iter_site = site_map.begin();

    for(; iter_site != site_map.end(); ++iter_site)
    {
        if(iter_site->second->cards.size() > 254)
        {
            log_error("呼叫:分站下卡数量过多:分站id=%d, 卡数=%d",
                      iter_site->first, iter_site->second->cards.size());
            continue;
        }

        std::vector<char> arr;

        int16_t cmd = 0x77ab;
        arr.push_back(cmd>>8 & 0xff);
        arr.push_back(cmd & 0xff);
        //分站地址 4字节,支持大小分站呼叫协议;added by zhuyf 2018/06/04
        //大小分站的全员呼叫,分站id要求4字节全为FF
        uint32_t anchor_id = (iter_site->second->is_call_all()? 0xffffffff : static_cast<uint32_t>(iter_site->first));
        memcpy_uint32(arr,anchor_id);

        //卡数
        arr.push_back(static_cast<char>(iter_site->second->cards.size()));
        //呼叫类型
        arr.push_back(static_cast<char>(iter_site->second->call_type_id));

        if(!iter_site->second->is_call_all())
        {
            //循环添加卡信息
            auto it_card = iter_site->second->cards.begin();
            for(; it_card != iter_site->second->cards.end(); ++it_card)
            {
                //呼叫类型
                arr.push_back(static_cast<char>(it_card->second->call_level_id));
                //卡类型
                arr.push_back(static_cast<char>(it_card->second->cardtype));
                //卡ID长度
                int id_len = 4;
                arr.push_back(static_cast<char>(id_len));
                //卡ID
                memcpy_uint32(arr, it_card->second->cardid);
            }
        }

        auto sit_ptr = sit_list::instance()->get(iter_site->first);
        if(!sit_ptr || !sit_ptr->m_clt)
        {
            log_error("在全局分站列表中找不到分站 或者sit_ptr->m_clt==null:分站id=%d", iter_site->first);
            continue;
        }

        int16_t len=arr.size()+2;
        int16_t crc=do_crc_1(arr,0);

        auto it= arr.begin();arr.insert(it,len&0xff);
        it= arr.begin();arr.insert(it,len>>8&0xff);

        arr.push_back(crc>>8&0xff);arr.push_back(crc&0xff);
        std::vector<char> arr2 = arr;
        sit_ptr->m_clt->send(std::move(arr));

        print_test(std::move(arr2), iter_site->first);
    }
}

void module_call::print_test(std::vector<char>&& arr, int siteid)
{
    std::string str("呼叫发送的数据帧,分站号=");
    str.append(std::to_string(siteid));
    str.append(":");

    char a[4]={0};
    for(std::vector<char>::size_type i=0; i<arr.size(); i++)
    {
        sprintf(a, "%02X ", static_cast<unsigned char>(arr[i]));

        str.append(std::string(a));
    }

    log_info("%s", str.c_str());
}

void module_call::rev_from_card_resp(std::shared_ptr<card_location_base> card_ptr)
{
    card_ptr->get_mine_tool()->m_status_call = CALL_SUCCESSED;
}

/*
web发给采集:发起呼叫
{
    cmd: 'call_card_req',
    data: {
      call_type_id: this.cal_type,      // 全员呼叫:0 定员呼叫:1
      call_time_out: this.choosedTime,  // 呼叫时长
      call_level_id: this.call_type_id, // 呼叫类型 一般呼叫:1 紧急呼叫:2
      user_name: xdata.userName,        // 呼叫人
      call_time: time,                  // 呼叫时间戳
      stations: [{ stationid: 0 }],     // 分站 0为全员
      cards: cards // 人员 0为全员      //旧代码为map格式 [{ stationid: 0 }]
    }
}
*/
void module_call::accept_call(sio::message::ptr const& data)
{
    int call_type = -1, call_level = 1, call_time_interval = -1;
    uint32_t call_time_out = 0;
    std::string user_name = "";

    call_time_interval = 5;

    if(!tool_map::try_get_value(call_type, JSON_KEY_CALL_CARD_CALL_TYPE, data)
            || !tool_map::try_get_value(call_level, JSON_KEY_CALL_CARD_CALL_LEVEL, data)
            || !tool_map::try_get_value(call_time_out, JSON_KEY_CALL_CARD_CALL_TIME_OUT, data)
            //|| !tool_map::try_get_value(call_time_interval, JSON_KEY_CALL_CARD_CALL_TIME, data)
            || !tool_map::try_get_value(user_name, JSON_KEY_CALL_CARD_USER_NAME, data)
            )
    {
        log_error("发起呼叫: 收到的json不对,解析不出call_type = %d, call_level = %d, \
                  call_time_out=%d, call_time_interval=%d,user_name=%s", call_type, call_level, call_time_out, call_time_interval, user_name.c_str());
        return;
    }

    if(user_name.empty())
    {
        log_error("发起呼叫: user_name用户名为空");
        return;
    }

    std::vector<call_card_ptr> result_arr;//结果集

    call_user_ptr user_ptr;
    if(CCT_CALL_ALL==call_type)// 全员
    {
        user_ptr = call_user_ptr(new call_user());

        user_ptr->call_time          = std::chrono::system_clock::now();
        user_ptr->call_time_out      = call_time_out;
        user_ptr->call_time_interval = call_time_interval;
        user_ptr->call_type_id       = call_type;
        user_ptr->call_level_id      = call_level;
        user_ptr->user_name          = user_name;

        call_card_ptr temp(new call_card());
        copy(user_ptr, temp);
        temp->cardid = CCT_CALL_ALL; //全员卡
        temp->call_state = CALL_ING;

        result_arr.push_back(temp);//增加到结果集中

        //添加全员卡
        user_ptr->cards.insert(std::make_pair(temp->cardid, temp));

        //更新用户信息
        std::lock_guard<std::mutex> lock(_mutex);
        _map[user_name]=user_ptr;
    }
    else// 定员: 如果有全员,定员不生效
    {
        std::lock_guard<std::mutex> lock(_mutex);

        auto user_map_ptr = _map.find(user_name);
        if(_map.end() == user_map_ptr)//没有这个用户就新建并加入
        {
            user_ptr=call_user_ptr(new call_user());
            _map[user_name]=user_ptr;
        }
        else//有这个用户
        {
            user_ptr=user_map_ptr->second;
            // 如果有全员,定员不生效
            auto card_temp = user_ptr->cards.find(CCT_CALL_ALL);
            if(user_ptr->cards.end() != card_temp)
            {
                return;
            }
        }

        //更新用户信息
        user_ptr->call_time=std::chrono::system_clock::now();
        user_ptr->call_time_out=call_time_out;
        user_ptr->call_time_interval = call_time_interval;
        user_ptr->call_type_id=call_type;
        user_ptr->call_level_id=call_level;
        user_ptr->user_name=user_name;

        std::vector<sio::message::ptr> card_vec;
        if(!tool_map::try_get_value(card_vec, JSON_KEY_CALL_CARD_CARDS, data) || card_vec.size() == 0)
        {
            log_error("发起呼叫,web发来的数据JSON_KEY_CALL_CARD_CARDS字段为空 或者不是数组");
            return;
        }

        add_cards_to_user(card_vec, user_ptr);

        for(auto& it:user_ptr->cards)//添加到结果集中
        {
            result_arr.push_back(it.second);
        }
    }

    //组装json发送给web
    if(!result_arr.empty())
    {
        response_accept_call(result_arr);
    }
}

//采集回复web发起呼叫
//{
//	'cmd': 'call_card_resp',
//	'data': [
//		["fjb", // 发起呼叫人
//		"0010000000001", // 呼叫的卡号
//		103, // 分站号
//		23431, // 发起呼叫时间
//		0, //
//		0 // 正在呼叫:2/结束呼叫/
//		]
//	]
//}
void module_call::response_accept_call(std::vector<call_card_ptr> cards)
{
    rapidjson::Document doc(rapidjson::kObjectType);
    auto& allocator = doc.GetAllocator();
    rapidjson::Value node_cards(rapidjson::kArrayType);

    //组装json发送给web
    to_node_array(node_cards, cards, allocator,false);

    doc.AddMember(JSON_ROOT_KEY_CMD,JSON_CMD_VALUE_CALL_CARD_RESPONSE, allocator);
    doc.AddMember(JSON_ROOT_KEY_VERSION, INTERFACE_VERSION, allocator);
    doc.AddMember(JSON_ROOT_KEY_DATA, node_cards, allocator);

    swsClientMgr.send(JSON_CMD_VALUE_PUSH, tool_json::doc_to_json(doc));
}


//web发给采集:取消呼叫
//{
//	cmd: 'call_card_cancel_req',
//	data: {
//	  call_type_id: type, // 全员/定员
//	  user_name: xdata.userName, // 取消人
//	  call_time: callTime, // 时间戳
//	  stations: this.stationid, // 分站
//	  cards: this.cards // 取消呼叫卡  //旧代码为map格式 [{ stationid: 0 }]
//	}
//}
void module_call::accept_cancel(sio::message::ptr const& node_data)
{
    int call_type = -1;//, call_level = -1;
    std::string user_name;
    int64_t call_time = 0;

    if(!tool_map::try_get_value(call_type, JSON_KEY_CALL_CARD_CALL_TYPE, node_data)
            || !tool_map::try_get_value(call_time, JSON_KEY_CALL_CARD_CALL_TIME, node_data)
            || !tool_map::try_get_value(user_name, JSON_KEY_CALL_CARD_USER_NAME, node_data)
            )
    {
        log_error("取消呼叫: 收到的json不对,解析不出int call_type = %d, call_time = %d,user_name=%s", call_type, call_time, user_name.c_str());
        return;
    }

    if(user_name.empty())
    {
        log_error("取消呼叫: user_name用户名为空");
        return;
    }

    call_user_ptr result_user_ptr(new call_user());
    result_user_ptr->call_type_id=call_type;
    //    result_user_ptr->call_level_id=call_level;
    result_user_ptr->call_time = std::chrono::system_clock::time_point(std::chrono::milliseconds(call_time));
    result_user_ptr->user_name=user_name;

    //取消呼叫有两种:
    //取消全员呼叫
    //对指定卡取消呼叫
    if(CCT_CALL_ALL==call_type)// 取消全员呼叫
    {
        //删除用户
        std::lock_guard<std::mutex> lock(_mutex);
        _map.erase(user_name);
    }
    else// 取消定员呼叫
    {
        std::vector<sio::message::ptr> card_vec;
        if(!tool_map::try_get_value(card_vec, JSON_KEY_CALL_CARD_CARDS, node_data) || card_vec.size() == 0)
        {
            log_error("取消呼叫: web发来的数据cards字段为空 或者不是数组");
            return;
        }

        std::lock_guard<std::mutex> lock(_mutex);

        call_user_ptr user_ptr(new call_user());
        auto it_map = _map.find(user_name);
        if(_map.end()!=it_map)//呼叫用户
        {
            user_ptr=it_map->second;
        }

        std::vector<sio::message::ptr>::const_iterator it_card = card_vec.begin();
        std::string s_card_id;
        for(; it_card != card_vec.end(); ++it_card)
        {
            if(!tool_map::try_get_value(s_card_id, JSON_KEY_CALL_CARD_CARD_ID, (*it_card)))
            {
                log_error("取消呼叫: web发来的数据 card_id 格式不对");
                continue;
            }

            uint32_t id = tool_other::id64_to_id(s_card_id);
            int type= tool_other::id64_to_type(s_card_id);

            log_info("取消呼叫: cardid=%d, cardtype=%d", id, type);

            call_card_ptr card_ptr(new call_card());
            card_ptr->cardid = id;
            card_ptr->cardtype = type;

            result_user_ptr->cards[card_ptr->cardid]=card_ptr;//增加到结果集中

            user_ptr->cards.erase(card_ptr->cardid);//删除这个卡
        }

        // 没有呼叫信息,删除该用户记录
        if(user_ptr->cards.empty())
        {
            _map.erase(user_name);
        }
    }

    //如果要取消呼叫的用户下没有卡,建一张CCT_CALL_ALL卡返回
    if(result_user_ptr->cards.empty())
    {
        //        result_user_ptr->call_level_id=call_level;
        //result_user_ptr->call_time=std::chrono::system_clock::now();
        result_user_ptr->call_time_out=0;
        result_user_ptr->call_type_id=call_type;
        result_user_ptr->user_name=user_name;

        call_card_ptr card_ptr(new call_card());
        card_ptr->cardid=CCT_CALL_ALL;

        result_user_ptr->cards[card_ptr->cardid]=card_ptr;
    }

    //转发给web
    response_accept_cancel(result_user_ptr);
}

/*
采集回复web:取消呼叫
{
    "user_name":"fjb", // 取消人
    "call_time": 23432, // 发起呼叫时间
    "stations":[{"stationid":102}], // 分站号
    "cards":[{"cardid":"0","cardtype":"1"}] // 取消的卡
}
*/
void module_call::response_accept_cancel(const call_user_ptr user_ptr)
{
    rapidjson::Document doc(rapidjson::kObjectType);
    auto& allocator = doc.GetAllocator();
    rapidjson::Value node_data(rapidjson::kObjectType);

    tool_json::add_member(node_data, JSON_KEY_CALL_CARD_USER_NAME, user_ptr->user_name, allocator);

    node_data.AddMember(JSON_KEY_CALL_CARD_CALL_TIME, tool_time::to_ms(user_ptr->call_time), allocator);
    node_data.AddMember(JSON_KEY_CALL_CARD_CALL_TYPE, user_ptr->call_type_id, allocator);

    rapidjson::Value node_cards(rapidjson::kArrayType);

    //加入取消呼叫的卡
    auto iter = user_ptr->cards.begin();
    for(;iter != user_ptr->cards.end();++iter)
    {
        rapidjson::Value node_card(rapidjson::kObjectType);

        tool_json::add_member(node_card, JSON_KEY_CALL_CARD_CARD_ID, iter->second->to_id64_str(), allocator);
        node_card.AddMember(JSON_KEY_CALL_CARD_CARD_TYPE_ID,iter->second->cardtype, allocator);

        node_cards.PushBack(node_card,allocator);
    }

    node_data.AddMember(JSON_KEY_CALL_CARD_CARDS, node_cards, allocator);

    doc.AddMember(JSON_ROOT_KEY_CMD, JSON_CMD_VALUE_CALL_CARD_CANCEL_RESPONSE, allocator);
    doc.AddMember(JSON_ROOT_KEY_VERSION, INTERFACE_VERSION, allocator);
    doc.AddMember(JSON_ROOT_KEY_DATA, node_data, allocator);

    //转发给web
    swsClientMgr.send(JSON_CMD_VALUE_PUSH, tool_json::doc_to_json(doc));
}

/*
登陆时,采集发送web:井下所有呼叫
{"cmd":"callcardlist","data":[
    ["fjb", // 发起呼叫人
    "0010000000001", // 呼叫的卡号
    103, // 分站号
    23431, // 发起呼叫时间
    0, //
    0 // 正在呼叫:2/结束呼叫/
    ]
]}
*/
std::string module_call::accept_login()
{
    std::vector<call_card_ptr> arr;

    get_all_call_cards(arr);

    if(arr.empty())
    {
        return "";
    }

    return to_call_card_list_json(arr);
}

std::string module_call::to_call_card_list_json(std::vector<call_card_ptr> arr)
{
    rapidjson::Document doc(rapidjson::kObjectType);
    auto& allocator = doc.GetAllocator();
    rapidjson::Value node_cards(rapidjson::kArrayType);

    to_node_array(node_cards, arr, allocator);

    doc.AddMember(JSON_ROOT_KEY_CMD, JSON_CMD_VALUE_CALL_CARD_LIST, allocator);
    doc.AddMember(JSON_ROOT_KEY_VERSION, INTERFACE_VERSION, allocator);
    doc.AddMember(JSON_ROOT_KEY_DATA, node_cards, allocator);

    return tool_json::doc_to_json(doc);
}

void module_call::add_cards_to_user(const std::vector<sio::message::ptr>& card_vec, call_user_ptr user_ptr)
{
    std::vector<sio::message::ptr>::const_iterator it_card = card_vec.begin();
    for(; it_card != card_vec.end(); ++it_card)
    {
        std::string s_card_id;
        if(!tool_map::try_get_value(s_card_id, JSON_KEY_CALL_CARD_CARD_ID, (*it_card))
                ||s_card_id.empty())
        {
            log_error("发起呼叫,web发来的数据 card_id 格式不对 或为空");
            continue;
        }

        uint32_t id = tool_other::id64_to_id(s_card_id);
        int type= tool_other::id64_to_type(s_card_id);

        log_info("发起呼叫 cardid=%d, cardtype=%d", id, type);

        call_card_ptr card_ptr(new call_card());
        card_ptr->cardid = id;
        card_ptr->cardtype = type;
        copy(user_ptr, card_ptr);

        card_ptr->call_state = CALL_ING;

        user_ptr->cards[card_ptr->cardid]=card_ptr;
    }
}

void module_call::get_user_all_call_cards(call_user_ptr& user_ptr,
                                          const std::unordered_map<uint64_t,std::shared_ptr<card_location_base>>& cardlist,
                                          std::vector<call_card_ptr>& out_data)
{
    auto& cards=user_ptr->cards;
    int status = CALL_ING;

    //如果是全员呼叫,增加所有卡
    auto card_it = cards.find(CCT_CALL_ALL);
    if(cards.end()!=card_it)
    {
        if(user_ptr->is_timeout())//呼叫超时, 清空全员卡, 并设置呼叫状态为结束
        {
            log_info("全员呼叫发送线程:呼叫用户超时,用户名=%s", user_ptr->user_name.c_str());

            cards.clear();
            status=CALL_END;
        }

        auto g_it=cardlist.begin();
        for(;g_it!=cardlist.end();++g_it)//如果是全员呼叫,增加所有卡
        {
            auto site_ptr = g_it->second->get_area_tool()->m_site;
            if(!site_ptr)
            {
                continue;
            }

            call_card_ptr card_ptr(new call_card());
            copy(user_ptr, card_ptr);
            card_ptr->cardid = g_it->second->m_id;
            card_ptr->cardtype = g_it->second->m_type;

            card_ptr->stationid=site_ptr->id();

            card_ptr->call_state=status;
            if(CALL_SUCCESSED == g_it->second->get_mine_tool()->m_status_call)
            {
                card_ptr->call_state = CALL_SUCCESSED;
            }
            else
            {
                g_it->second->get_mine_tool()->m_status_call = CALL_ING;
            }

            if(card_ptr->is_timeout())
            {
                g_it->second->get_mine_tool()->m_status_call = 0;
            }
            card_ptr->is_display = g_it->second->m_display;

            out_data.push_back(card_ptr);
        }

        return;
    }

    //定员呼叫
    auto iter_card = cards.begin();
    for(;iter_card!=cards.end();++iter_card)
    {
        //增加到结果集中
        out_data.push_back(iter_card->second);

        auto g_card = cardlist.find(iter_card->second->to_id64());
        if(cardlist.end()==g_card)//在全局卡列表中没有这张卡,
        {
            log_error("定员呼叫发送线程:全局卡列表中没有这张卡,卡id=%d,卡类型=%d",
                      iter_card->second->cardid, iter_card->second->cardtype);

            iter_card->second->call_state = CALL_FAILED;
            cards.erase(iter_card--); //在用户下删除这张卡

            continue;
        }

        auto site_ptr = g_card->second->get_area_tool()->m_site;
        if(!site_ptr)
        {
            log_error("定员呼叫发送线程:全局卡列表中这张卡已经上井或无效,卡id=%d,卡类型=%d",
                      iter_card->second->cardid, iter_card->second->cardtype);

            iter_card->second->call_state = CALL_FAILED;
            cards.erase(iter_card--); //在用户下删除这张卡

            continue;
        }

        //更新卡的分站id
        iter_card->second->stationid = site_ptr->id();

        if(CALL_SUCCESSED == g_card->second->get_mine_tool()->m_status_call)
        {
            iter_card->second->call_state = CALL_SUCCESSED;
        }
        else
        {
            g_card->second->get_mine_tool()->m_status_call = CALL_ING;
        }

        if(iter_card->second->is_timeout())//呼叫超时
        {
            log_info("定员呼叫发送线程:呼叫卡超时,用户名=%s,卡id=%d,卡类型=%d",
                     iter_card->second->user_name.c_str(),
                     iter_card->second->cardid, iter_card->second->cardtype);

            iter_card->second->call_state = CALL_END;
            if(CALL_SUCCESSED == g_card->second->get_mine_tool()->m_status_call)
            {
                iter_card->second->call_state = CALL_SUCCESSED;
                g_card->second->get_mine_tool()->m_status_call = 0;
            }
            cards.erase(iter_card--);//在用户下删除这张卡
        }
    }
}


/**
* @brief 系统自动发送呼叫给指定的卡
*/
void module_call::system_call_apoint(int card_id,int card_type)
{
    int call_type = -1, call_level = 1, call_time_interval=-1;
    uint32_t call_time_out = 0;
    std::string user_name = "system_apoint";

    std::vector<call_card_ptr> result_arr;//结果集

    call_user_ptr user_ptr;
    std::lock_guard<std::mutex> lock(_mutex);
    auto user_map_ptr = _map.find(user_name);
    if(_map.end() == user_map_ptr)//没有这个用户就新建并加入
    {
        user_ptr=call_user_ptr(new call_user());
        _map[user_name]=user_ptr;
    }
    else//有这个用户
    {
        user_ptr=user_map_ptr->second;
    }

    //更新用户信息
    user_ptr->call_time=std::chrono::system_clock::now();
    user_ptr->call_time_out=call_time_out;
    user_ptr->call_time_interval = call_time_interval;
    user_ptr->call_type_id=call_type;
    user_ptr->call_level_id=call_level;
    user_ptr->user_name=user_name;

    call_card_ptr c_card_ptr(new call_card());
    c_card_ptr->cardid = card_id;
    c_card_ptr->cardtype = card_type;
    copy(user_ptr, c_card_ptr);
    c_card_ptr->call_state = CALL_ING;

    user_ptr->cards[c_card_ptr->cardid]=c_card_ptr;

    for(auto& it:user_ptr->cards)//添加到结果集中
    {
        result_arr.push_back(it.second);
    }
    log_info("发起呼叫 cardid=%d, cardtype=%d", card_id,card_type);

    //组装json发送给web
    response_accept_call(result_arr);
}
/**
 * @brief 系统自动发送呼叫给指定的卡
 */
void module_call::system_cancel_call_apoint(int card_id,int card_type)
{
    int call_type = -1;//, call_level = -1;
    std::string user_name = "system_apoint";
    int64_t call_time;

    call_user_ptr result_user_ptr(new call_user());
    result_user_ptr->call_type_id=call_type;
    //    result_user_ptr->call_level_id=call_level;
    result_user_ptr->call_time = std::chrono::system_clock::time_point(std::chrono::milliseconds(call_time));
    result_user_ptr->user_name=user_name;

    std::lock_guard<std::mutex> lock(_mutex);

    call_user_ptr user_ptr(new call_user());
    auto it_map = _map.find(user_name);
    if(_map.end()!=it_map)//呼叫用户
    {
        user_ptr=it_map->second;
    }
    if (user_ptr->cards.find(card_id) == user_ptr->cards.end())
    {
        return ;
    }
    call_card_ptr c_card_ptr(new call_card());
    c_card_ptr->cardid = card_id;
    c_card_ptr->cardtype = card_type;

    result_user_ptr->cards[c_card_ptr->cardid]=c_card_ptr;//增加到结果集中

    user_ptr->cards.erase(c_card_ptr->cardid);//删除这个卡

    log_info("取消呼叫: cardid=%d, cardtype=%d", card_id,card_type);
    // 没有呼叫信息,删除该用户记录
    if(user_ptr->cards.empty())
    {
        _map.erase(user_name);
    }

    response_accept_cancel(result_user_ptr);
}

/*
 * @brief       发送防碰撞告警
 * @param       const std::map<int, call_card>& cards       key为车id,val为人卡信息
 * @return
 * @note
 * @warning
 * @bug
 *
 * */
void module_call::send_anti_collision(const std::map<int, call_card>& cards)
{
    std::vector<call_card_ptr> vt_cards;
    std::string vmsg = "";
    std::string pmsg = "";

    for(auto c : cards){
        char buf[100] = {0};
        snprintf(buf, 100, "%d,", c.second.cardid);

        switch(c.second.cardtype){
            case 1:
                pmsg += std::string(buf);
                break;
            case 2:
                vmsg += std::string(buf);
                break;
        }
        
        vt_cards.push_back(std::make_shared<call_card>(c.second));
    }
    log_info("[anti_coll] vehicle's cid = %s, person's cid = %s", vmsg.c_str(), pmsg.c_str());

    call_site_map site_map;
    get_site_map(vt_cards, site_map);
    //log_info("[anti_coll] site's size = %d", site_map.size());
    if(!site_map.empty()){
        send_to_sites(site_map);
    }
}

std::string module_call::get_json_anti_collision()
{
    rapidjson::Document doc(rapidjson::kObjectType);
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
    doc.SetObject();

    rapidjson::Value data(rapidjson::kArrayType);
    auto tmp = event_list::instance()->m_map;
    for(auto it_ev = tmp.cbegin(); it_ev != tmp.cend(); ++it_ev)
    {
        if(ET_PERSON_VEHICLE_ANTI_COLLISION != it_ev->second->m_ev_type)
        {
            continue;
        }
     
        rapidjson::Value obj(rapidjson::kObjectType);
        
        //rapidjson::Value vid(rapidjson::kObjectType); 
        //vid.SetInt(atoi(it_ev->second->m_obj_id.c_str()));

        /*std::string str_vid = "";
        char szID[32] = {0};
        sprintf(szID, "%03d%.10d", 2, atoi(it_ev->second->m_obj_id.c_str()));
        str_vid = szID;
        */

        rapidjson::Value val;
        obj.AddMember("vid", val.SetString(it_ev->second->m_obj_id.c_str(), allocator), allocator);

        rapidjson::Value elems(rapidjson::kArrayType);
        std::string msg = it_ev->second->m_desc;
        std::vector<std::string> vt_msg;
        boost::split(vt_msg, msg, boost::is_any_of(";"));
        for(auto it_elem : vt_msg){
            std::vector<std::string> vt_cid_d;
            boost::split(vt_cid_d, it_elem, boost::is_any_of(","));

            if(vt_cid_d.size()<2){
                continue;
            }

            rapidjson::Value e(rapidjson::kArrayType);
            rapidjson::Value o(rapidjson::kObjectType);

            //o.SetInt(atoi(vt_cid_d[0].c_str()));
            /*memset(szID, 0, 32);
            sprintf(szID, "%03d%.10d", 1, atoi(vt_cid_d[0].c_str()));
            str_vid = szID;
            */
            o.SetString(tool_other::to_cid(1, atoi(vt_cid_d[0].c_str())).c_str(), allocator);
            e.PushBack(o, allocator);

            o.SetDouble(atof(vt_cid_d[1].c_str()));
            e.PushBack(o, allocator);
            
            elems.PushBack(e, allocator);   
        }
        obj.AddMember("pid", elems, allocator);

        std::string t = tool_time::to_str(it_ev->second->m_cur_time);
        tool_json::add_member(obj, "start_time", t, allocator);

        data.PushBack(obj, allocator);
    }

    if(!data.Size()){
        return "";
    }

    doc.AddMember(JSON_ROOT_KEY_CMD, "pv_anti_coll", allocator);
    doc.AddMember(JSON_ROOT_KEY_VERSION, INTERFACE_VERSION, allocator);
    doc.AddMember(JSON_ROOT_KEY_DATA, data, allocator);

    rapidjson::StringBuffer sb;
    rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
    doc.Accept(writer);

    return sb.GetString();
}