#include <iostream>
#include <fstream>
#include "JsonModule.h"
#include "SocketModule.h"
#include "../utility/utility.h"
#include "../utility/zini.h"
//#include "SQLiteModule.h"

#ifdef WIN32
#include <Windows.h>
//#pragma comment(lib,"../bin/sqlite3.lib")
#else
#include <pthread.h>
#endif

#define ELPP_NO_DEFAULT_LOG_FILE
#include "../3rdParty/easylogging/easylogging++.h"

INITIALIZE_EASYLOGGINGPP

std::string g_init_data;
std::string g_init_data_ods_back;

std::string g_set_pos_priority;               //设置pos优先级
std::string g_set_pos_priority_ods_back;

std::string ods_ip;
std::string pos_ip = "127.0.0.1";
int ods_push_port;
int ods_recv_port;
int client_listen_port;
int pos_listen_port;
//std::vector<orderSendFailedObj> vecFailedOrders;
//bool bRetryThreadRunning=false;     //retry线程是否正在运行
bool bInitDone=false;      //初始化完成
bool bPriorityDone=true;   //设置POS优先级
//SQLite sqlite;

//函数，订单信息发送给pos
bool order_send_to_pos(IN std::string &order_json,IN std::string &ods_json,OUT std::string &back_json);
//失败订单写入vector及sqlite
//void write_failed_order(IN std::string &order_json);

void logRolloutHandler(const char* filename, std::size_t size)
{
    /// 备份日志
    //std::string strLogPath = GetProcDir();
    //strLogPath.append(filename);
    std::cout<<"bk filename:"<<filename<<std::endl;
    std::stringstream ss;
    ss << "mv " << filename << " "<<filename<<"_bk";
    system(ss.str().c_str());
}
#ifdef WIN32
DWORD WINAPI listen_pos_func(LPVOID lpParamter)
#else
void* listen_pos_func(void* arg)
#endif // WIN32
{
    TCPServer server;
    JsonModule jsonTool;

    if( server.doListen(client_listen_port) )
    {
        LOG(INFO) << "local listen port: [" << client_listen_port << "] successful";
    }else
    {
        LOG(INFO) << "local listen port: [" << client_listen_port << "] failed, maybe instance is exist,exit!!!";
        exit(1);
    }

    while(true)
    {
        TCPClient pos;

        std::string posRequestData;
        std::string requestOdsData;
        std::string responseData;

        if( server.accept(pos) )
        {
            char tmpBuf[BUF_SIZE] = {0};
            if( pos.read(tmpBuf, sizeof(tmpBuf)) )
            {
                posRequestData = tmpBuf;
                // 如果为初始化请求则通过长连接socket发送
                //bool isInit=jsonTool.isInitData(posRequestData);
                int reqType=jsonTool.getPushType(posRequestData.data());
                LOG(INFO)<<"pos reqType:"<<reqType;
                if(reqType==REQUEST_TYPE_INIT)
                {
                    bInitDone=false;
                    if( jsonTool.checkInitData(posRequestData, pos_listen_port) )
                    {
                        g_init_data_ods_back.clear();
                       // g_init_data = posRequestData;
                        LOG(INFO) <<"INIT POS ===>> PLUGIN:"<<posRequestData.c_str();
                        jsonTool.convertInitDataPos2Ods(posRequestData,g_init_data);
                        //jsonTool.getPosResponseData(100, "successful!", responseData);
                        LOG(INFO) <<"INIT PLUGIN ===>> ODS:"<<g_init_data.c_str();
                        //等待ods返回初始化结果
                        while(true){
                            if(!g_init_data_ods_back.empty()){
                                jsonTool.getInitBackData(g_init_data_ods_back.data(),responseData);
                                LOG(INFO) <<"INIT PLUGIN ===>> POS:"<<responseData.c_str();
                                break;
                            }
                            else{
                                LOG(INFO)<<"wait for ods init back data";
                                os_sleep(3);
                            } 
                        }
                        jsonTool.setInitData(posRequestData.data());   //把初始化数据暂存起来
                    }else
                    {
                        jsonTool.getPosResponseData(101, "invalid initdata!", responseData);
                    }
                }
                else if(reqType==REQUEST_TYPE_POS_PRIORITY){
                    if(bInitDone){
                        //未完成，缺接口
                        bPriorityDone=false;
                        LOG(INFO)<<"POS send priority data:"<<posRequestData.data();
                        g_set_pos_priority_ods_back.clear();
                        jsonTool.convertSetPosPriorityDataPos2Ods(posRequestData,g_set_pos_priority);
                        //等待ods返回初始化结果
                        while(true){
                            if(!g_set_pos_priority_ods_back.empty()){
                                jsonTool.getSetPosPriorityBackData(g_set_pos_priority_ods_back.data(),responseData);
                                break;
                            }
                            else{
                                LOG(INFO)<<"wait for ods priority back data";
                                os_sleep(1);
                            }
                        }

                    }
                }
                else if(reqType==REQUEST_TYPE_GOODS_CHANGE){
                    std::string posReq = charset_g2u(posRequestData);
                    LOG(INFO)<<"POS send goods change data:"<<posReq.data();
                    jsonTool.getPosResponseData(100, "success", responseData);
                }
                else
                {
                    LOG(INFO)<<"REQ POS ===>> PLUGIN:"<<posRequestData.data();
                    // 将POS请求数据转换为中台可接受数据格式
                    if( jsonTool.convertDataPos2Ods(posRequestData, requestOdsData) )
                    {
                        LOG(INFO)<<"REQ PLUGIN ===>> ODS:"<<requestOdsData.data();
                        // 同步阻塞发送到ODS并等待返回
                        TCPClient ods;
                        if( ods.doConnect(ods_recv_port, ods_ip.c_str()) )
                        {
                            if( ods.send(requestOdsData) )
                            {
                                std::string tmp;
                                if( ods.receive(tmp) )
                                {
                                    LOG(INFO)<<"REQ ODS ===>> PLUGIN:"<<tmp.data();
                                    jsonTool.getPosResponseData(tmp,posRequestData, responseData);    
                                }else
                                {
                                    jsonTool.getPosResponseData(101, "receive data from [ODS] failed!", responseData);
                                }
                            }else
                            {
                                jsonTool.getPosResponseData(101, "send data to [ODS] failed!", responseData);
                            }

                            ods.close();
                        }else
                        {
                            jsonTool.getPosResponseData(101, "connect [ODS] failed!", responseData);
                        }
                    }else
                    {
                        jsonTool.getPosResponseData(101, "convert data to [ODS] format failed!", responseData);
                    }
                }

                // TODO待加入重试机制
                LOG(INFO) << "PLUGIN ===>>POS:"<<responseData.data();
                pos.write(responseData.c_str());
                pos.close();
                if(reqType==REQUEST_TYPE_INIT){
                    bInitDone=true; //初始化完成，可以接收订单
                }
                if(reqType==REQUEST_TYPE_POS_PRIORITY){
                    bPriorityDone=true; //设置pos优先级完成
                }
                LOG(INFO)<<"SEND END";
            }else
            {
                LOG(INFO) << "recv pos pushData failed";
            }
        }else
        {
            LOG(INFO) << "accept pos connect failed";
        }
    }
#ifdef WIN32
	return 0;
#endif // WIN32
}

// //发送POS订单失败，重新发送线程
// void* retry_send_pos_func(void* arg)
// {
//     bRetryThreadRunning=true;
//     JsonModule jsonTool;
//     std::vector<orderSendFailedObj>::iterator Iter;
//     for(Iter = vecFailedOrders.begin(); Iter != vecFailedOrders.end();) {
//         Iter = vecFailedOrders.begin();  //一直发送第一个，直到发送成功
//         std::string back_json;
//         std::string ods_json=(*Iter).order_json;
//         std::string order_json;
//         if( jsonTool.convertDataOds2Pos(ods_json, order_json) ){
//             if(order_send_to_pos(order_json,ods_json,back_json)){
//                 char lpSql[200] = {0};
//                 sprintf(lpSql, "delete from fmOrderFailed where id = %lld",(*Iter).timestamp); 
//                 LOG(INFO)<<"sql:"<<lpSql;   

//                 if(!sqlite.remove(lpSql)){
//                     LOG(ERROR) << "remove failed:"<<lpSql;
//                 }

//                 vecFailedOrders.erase(Iter); //Iter为删除元素的下一个元素的迭代器     
//             }
//         }

//         sleep(1);  //等待1s,再次尝试发送
//     }
//     LOG(INFO)<<"retry_send_pos_func thread done";
//     bRetryThreadRunning=false;
//     pthread_detach(pthread_self());
// }


int main()
{   
    /* Mark
     * 与ODS通信全部加数据头(长度)
     * 与POS通信全部不加数据头
     * end*/
#ifdef WIN32
    WSADATA transData;
    WSAStartup(MAKEWORD(2, 2), &transData);
    ShowWindow(GetConsoleWindow(), SW_HIDE); //隐藏窗口，后台运行
#else
    signal(SIGPIPE, SIG_IGN);
#endif
    
    // 初始化日志
    el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);
    std::string strBinPath = GetProcDir();
    std::string strLogPath(strBinPath.data());
    strLogPath.append("log.conf");
    el::Configurations conf(strLogPath.data());
    /// 设置全部logger的配置
    el::Loggers::reconfigureAllLoggers(conf);
    /// 注册回调函数
    el::Helpers::installPreRollOutCallback(logRolloutHandler);

    LOG(INFO)<<"---------software start---------";
    //sqlite初始化
    
    // if(!sqlite.initSQLite()){
    //     LOG(INFO)<<"initSQLite failed";
    //     return 0;
    // }

    // 读取配置文件信息
    std::string strIniPath(strBinPath.data());
    strIniPath.append("config.ini");

    LOG(INFO) << "strIniPath: " << strIniPath.data();
    ods_ip = ZIni::readString("ODS","ip", "", strIniPath.c_str());
    ods_push_port = ZIni::readInt("ODS", "pushPort", 0, strIniPath.c_str());
    ods_recv_port = ZIni::readInt("ODS", "recvPort", 0, strIniPath.c_str());
    int ods_socket_timeout = ZIni::readInt("ODS", "socketTimeout", 0, strIniPath.c_str());

    pos_ip = ZIni::readString("POS","ip", "", strIniPath.c_str());
    pos_listen_port = ZIni::readInt("POS","port", 0, strIniPath.c_str());

    client_listen_port = ZIni::readInt("SYS", "port", 0, strIniPath.c_str());

    LOG(INFO) << "[ODS]ip: " << ods_ip.data()
              << "-push port: " << ods_push_port
              << "-recv port: " << ods_recv_port
              << "-socket timeout: " << ods_socket_timeout;
    LOG(INFO) << "[POS]ip: " << pos_ip
              << "-listen port: " << pos_listen_port;
    LOG(INFO) << "[Local]listen port: " << client_listen_port;
    //end

#ifdef WIN32
	HANDLE hTakeway = CreateThread(NULL, 0, listen_pos_func, NULL, 0, NULL);
#else
	// 监听POS请求的线程
	pthread_t listen_pos_id;

	/*创建 listen_pos 线程*/
	if (pthread_create(&listen_pos_id, NULL, listen_pos_func, NULL))
		LOG(INFO) << "create listen_pos thread failed";

#endif // WIN32

    TCPClient ods;
    JsonModule jsonTool;

    while(true)
    {
        std::string odsPushData;
        std::string pushPosData;
        std::string responseData;

        // 判断是否成功连接ODS
        if( !ods.isValid() )
        {
            if( ods.doConnect(ods_push_port, ods_ip.c_str()) )
            {
                LOG(INFO) << "connect ODS successful";
                ods.setSocketTimeout(ods_socket_timeout);   //设置超时时间10s
                // 注册socket信息
                while(true)
                {
                    //g_init_data = "{\"fm_cmd\": 1000,\"storeId\": \"208888\",\"pos_id\": \"0001\",\"operator_id\": \"00001\",\"business_date\": \"20171225\",\"is_master\": true,\"listen_port\": 3289,\"ver\":1}";

                    if(!g_init_data.empty())
                     {
                        if( ods.send(g_init_data) )
                        {
                            ods.receive(odsPushData);
                            g_init_data_ods_back=odsPushData;
                            LOG(INFO)<<"INIT ODS ===>> PLUGIN:"<<odsPushData.data();
                            int count=0;
                            while(!bInitDone){
                                LOG(INFO)<<"wait for init done";
                                if( !ods.isValid() ){
                                    LOG(INFO)<<"ods is not valid";
                                    os_sleep(1); //防止在ods挂掉后狂刷日志
                                    break;
                                }
                                os_sleep(1);
                                count++;
                                //如果10s没有初始化完成，则跳出循环，重新连接
                                if(10==count){
                                    ods.close();
                                    break;
                                }
                            }
                            break;

                            // //如果连接非法，跳出循环重新连接
                            // if( !ods.isValid() ){
                            //     break;
                            // }

                            
                            // //检测是否有发送失败的订单，如果有的话，启动线程，先发送原先失败的订单
                            // sqlite.query("select * from fmOrderFailed",vecFailedOrders);
                            // LOG(INFO)<<"vecFailedOrders size:"<<vecFailedOrders.size();
                            // if(vecFailedOrders.size()>0){
                            //     pthread_t retry_thread_id;
                            //     if(pthread_create(&retry_thread_id,NULL,retry_send_pos_func,NULL))
                            //         LOG(INFO) << "create retry_send_pos_func thread failed";
                            // }
                        }
                    }
                    else{
                        LOG(INFO)<<"Haven't receive init data";
                    }
                    os_sleep(3);
                    continue;
                }
            }else
            {
                LOG(INFO) << "connect ODS failed";
                os_sleep(5);
                continue;
            }
        }

        if(!bPriorityDone){
            LOG(INFO)<<"ODS set priority send:"<<g_set_pos_priority.data();
            if( ods.send(g_set_pos_priority) )
            {
                ods.receive(odsPushData);
                g_set_pos_priority_ods_back=odsPushData;
                LOG(INFO)<<"ODS set priority back:"<<odsPushData.data();
            }
        }

        if( ods.receive(odsPushData) )
        {
            LOG(INFO) << "---------------- ODS ===>> PLUGIN  ---------------";
            LOG(INFO) << odsPushData;
            if(!jsonTool.isHeartbeatData(odsPushData.data())){
                if( jsonTool.convertDataOds2Pos(odsPushData, pushPosData) )
                {
                    LOG(INFO) << "----------- PLUGIN ===>> POS ------------";
                    LOG(INFO) << pushPosData;
                    order_send_to_pos(pushPosData,odsPushData,responseData);
                    // if(!order_send_to_pos(pushPosData,odsPushData,responseData)){
                    //     write_failed_order(odsPushData);
                    //     if(!bRetryThreadRunning){   //如果线程没有在运行
                    //         pthread_t retry_thread_id;
                    //         /*创建 retry send 线程*/
                    //         if(pthread_create(&retry_thread_id,NULL,retry_send_pos_func,NULL))
                    //             LOG(INFO) << "create retry_send_pos_func thread failed";
                    //     }
                    // }
                }else
                {
                    jsonTool.getOdsResponseData(101, "convert data to [POS] format failed!", responseData);
                }

                // TODO待加入重试机制
                LOG(INFO) << "PLUGIN ===>> ODS:"<<responseData.data();
                //test
                //responseData="{\"fm_cmd\": 2,\"order_id\" : \"1234\",\"status\" : 1,\"channel\" : \"1234\",\"status_code\" : 100,\"msg\" : \"\"}";

                bool rlt = ods.send(responseData);
                LOG(INFO)<<"send to ods result:"<<rlt;
            }
            else{
                if(!bInitDone){
                    ods.setValid(false);
                    LOG(INFO)<<"maybe pos restart,reconnect!!!";
                }
            }

        }else
        {
            ods.close();
            LOG(INFO) << "recv ODS pushData failed or timeout";
        }
    }
    /// 注销回调函数  
    el::Helpers::uninstallPreRollOutCallback();
#ifdef WIN32
    WSACleanup();
#endif
    //sqlite.closeSQLite();
    return 0;
}

bool order_send_to_pos(IN std::string &order_json,IN std::string &ods_json,OUT std::string &back_json)
{
    bool rlt=true;
    TCPClient pos;
    JsonModule jsonTool;
    std::string tmp="{\"status_code\": 102, \"msg\": \"connect pos failed!\"}";
    if( pos.doConnect(pos_listen_port, pos_ip.c_str()) )
    {
        if( pos.write(order_json.c_str()) )
        {
            char tmpBuf[BUF_SIZE] = {0};
            if( pos.read(tmpBuf,sizeof(tmpBuf)) )
            {
                LOG(INFO) << "POS ===>> PLUGIN:"<<tmpBuf;
                tmp=tmpBuf;
                //pos发送过来的数据为gb2312编码，需要转换为utf8
                 //std::string tmpUtf8= charset_g2u(tmp);
                 //LOG(INFO)<<"gb2312 to utf8:"<<tmpUtf8.data();
                 //jsonTool.getOdsResponseData(tmpUtf8, order_json, responseData);
            }else
            {
                rlt=false;
            }
        }else
        {
            rlt=false;
        }

        pos.close();
    }else
    {
        rlt=false;
    }
    jsonTool.getOdsResponseData(tmp, order_json,ods_json, back_json);
    
    return rlt;
}

// void write_failed_order(IN std::string &order_json)
// {
//     orderSendFailedObj orderFailedObj;
//     orderFailedObj.timestamp=timestamps_milliseconds();
//     orderFailedObj.order_json=order_json;
//     vecFailedOrders.push_back(orderFailedObj);
//     LOG(INFO)<<"---------------create timestamp:"<<orderFailedObj.timestamp<<"   vector size:"<<vecFailedOrders.size();
    
//     char* lpSql = new char[BUF_SIZE];
//     sprintf(lpSql, "insert into fmOrderFailed(id,msg) values(%lld,'%s')",orderFailedObj.timestamp,orderFailedObj.order_json.c_str());    

//     if(!sqlite.insert(lpSql)){
//         LOG(ERROR) << "write sqlite failed:"<<lpSql;
//     }
    
//     delete[] lpSql;
// }
