#include "module_call.h"

#include <boost/bind.hpp>
#include <vector>
#include <set>
#include <string>
#include <chrono>
#include<algorithm>

/**
 * @brief 呼叫类型 全员 定员
 */
enum CALL_CARD_TYPE
{
    /// 全员呼叫
    CCT_CALL_ALL = 0,
    /// 定员
    CCT_CALL_APOINT=1,
};

/**
 * @brief 呼叫等级 一般呼叫  紧急呼叫
 */
enum CALL_CARD_LEVEL
{
    /// 呼叫等级: 1  一般呼叫
    CALL_LEVEL_NORMAL=1,
    /// 呼叫等级: 2  紧急呼叫
    CALL_LEVEL_CRITICAL=2
};

/**
 * @brief 呼叫状态
 */
enum CALL_STATE{
    ///无呼叫信息
    CALL_NONE = 0,
    ///呼叫成功
    CALL_SUCCESSED = 1,
    ///呼叫中
    CALL_ING = 2,
    ///呼叫失败
    CALL_FAILED = 3,

    ///呼叫结束
    CALL_END=100
};

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));

    //将呼叫命令发送给标识卡终端
}

/*
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(const rapidjson::Document& node_data)
{
    int call_type = -1, call_level = -1, call_time_out;
    std::string user_name;

    if(!tool_json::try_get_value(call_type, JSON_KEY_CALL_CARD_CALL_TYPE, node_data)
            || !tool_json::try_get_value(call_level, JSON_KEY_CALL_CARD_CALL_LEVEL, node_data)
            || !tool_json::try_get_value(call_time_out, JSON_KEY_CALL_CARD_CALL_TIME_OUT, node_data)
            || !tool_json::try_get_value(user_name, JSON_KEY_CALL_CARD_USER_NAME, node_data)
            )
    {
        log_error("收到的json不对，解析不出int call_type = -1, call_level = -1, call_time_out，user_name");
        return;
    }

    if(user_name.empty())
    {
        log_error("user_name用户名为空");
        return;
    }

    std::vector<call_card_ptr> 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_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; //全员卡

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

        //添加全员卡
        user_ptr->cards.insert(std::make_pair(CCT_CALL_ALL, 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(user_map_ptr==_map.end())//没有这个用户就新建并加入
        {
            user_ptr=call_user_ptr(new call_user());
            _map[user_name]=user_ptr;
        }
        else//有这个用户
        {
            user_ptr=user_map_ptr->second;
            // 如果有全员，定员不生效
            if(user_ptr->cards.size()==1 && CCT_CALL_ALL == user_ptr->cards[CCT_CALL_ALL]->cardid)
            {
                return;
            }
        }

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

        auto node_cards_ptr = node_data.FindMember(JSON_KEY_CALL_CARD_CARDS);
        if(node_data.MemberEnd()==node_cards_ptr)
        {
            return;
        }
        const rapidjson::Value& node_cards = node_cards_ptr->value;
        if(!node_cards.IsArray())
        {
            return;
        }

        add_cards_to_user(call_level, node_cards, user_ptr);

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

    //组装json发送给web
    if(!arr.empty())
    {
        response_accept_call(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);

    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(const rapidjson::Document& node_data)
{
    int call_type = -1, call_level = -1;
    std::string user_name;

    if(!tool_json::try_get_value(call_type, JSON_KEY_CALL_CARD_CALL_TYPE, node_data)
            || !tool_json::try_get_value(call_level, JSON_KEY_CALL_CARD_CALL_LEVEL, node_data)
            || !tool_json::try_get_value(user_name, JSON_KEY_CALL_CARD_USER_NAME, node_data)
            )
    {
        log_error("收到的json不对，解析不出int call_type = -1, call_level = -1，user_name");
        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->user_name=user_name;

    //取消呼叫有两种：
    //取消全员呼叫
    //对指定卡取消呼叫
    if(CCT_CALL_ALL==call_type)// 取消全员呼叫
    {
        //删除用户
        std::lock_guard<std::mutex> lock(_mutex);
        _map.erase(user_name);
    }
    else// 取消定员呼叫
    {
        auto node_cards_ptr = node_data.FindMember(JSON_KEY_CALL_CARD_CARDS);
        if(node_data.MemberEnd()==node_cards_ptr)
        {
            return;
        }
        const rapidjson::Value& node_cards = node_cards_ptr->value;
        if(!node_cards.IsArray())
        {
            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;
        }

        uint64_t id_card;
        for(rapidjson::SizeType i = 0; i < node_cards.Size(); ++i)
        {
            if(!tool_json::try_get_value( id_card, JSON_KEY_CALL_CARD_CARD_ID, node_cards[i])
                    || 0==id_card
                    )
            {
                continue;
            }

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

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

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

        // 没有呼叫信息，删除该用户记录
        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);

    node_data.AddMember(JSON_KEY_CALL_CARD_USER_NAME, rapidjson::StringRef(user_ptr->user_name.c_str()), allocator);
    node_data.AddMember(JSON_KEY_CALL_CARD_CALL_TIME, tool_time::to_ms(user_ptr->call_time), 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);
        node_card.AddMember(JSON_KEY_CALL_CARD_CARD_ID,iter->second->cardid, 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));
}

//void module_call::get_cancel_user_info(const call_user_ptr user_ptr,
//                                       const rapidjson::Value& node_cards, call_user_ptr& result_user_ptr)
//{
//    copy(user_ptr, result_user_ptr);

//    uint16_t cardid;
//    for(rapidjson::SizeType i = 0; i < node_cards.Size(); ++i)
//    {
//        call_card_ptr card_ptr;
//        const rapidjson::Value& node = node_cards[i];
//        if(!node.IsUint64() || !find_card(user_ptr, cardid=node.GetUint64(), card_ptr))
//        {
//            continue;
//        }

//        user_ptr->cards.erase(cardid);//从呼叫用户卡中删除

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

/*
登陆时，采集发送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(int call_level, const rapidjson::Value& node_cards, call_user_ptr user_ptr)
{
    uint64_t id_card;
    for(rapidjson::SizeType i = 0; i < node_cards.Size(); ++i)
    {
        if(!tool_json::try_get_value( id_card, JSON_KEY_CALL_CARD_CARD_ID, node_cards[i])
                || 0==id_card
                )
        {
            continue;
        }

        call_card_ptr card_ptr(new call_card());
        card_ptr->cardid = id_card;
        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;
    //如果是全员呼叫，增加所有卡
    if(cards.size()==1 && CCT_CALL_ALL == cards[0]->cardid)
    {
        uint32_t seconds = tool_time::elapse_seconds(user_ptr->call_time);
        if(seconds > user_ptr->call_time_out*60)//呼叫超时, 清空全员卡, 并设置呼叫状态为结束
        {
            cards.clear();
            status=CALL_END;
        }

        auto g_it=cardlist.begin();
        for(;g_it!=cardlist.end();++g_it)//如果是全员呼叫，增加所有卡
        {
            call_card_ptr card_ptr(new call_card());
            copy(user_ptr, card_ptr);
            card_ptr->cardid = g_it->second->m_id;
            card_ptr->stationid=g_it->second->m_site_id;

            card_ptr->call_state=status;

            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->cardid);
        if(cardlist.end()==g_card)//在全局卡列表中没有这张卡，
        {
            iter_card->second->call_state = CALL_FAILED;

            cards.erase(iter_card--); //在用户下删除这张卡
            continue;
        }

        //更新卡的分站id
        iter_card->second->stationid = g_card->second->m_site_id;

        uint32_t seconds = tool_time::elapse_seconds(iter_card->second->call_time);
        if(seconds > iter_card->second->call_time_out*60)//呼叫超时
        {
            iter_card->second->call_state = CALL_END;

            cards.erase(iter_card--);//在用户下删除这张卡
        }
    }
}


