#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "gttoolkitext.h"
#include "gt.h"
#include "gterror.h"
#include "gtstruct.h"
#include "gtencrypt.h"
#include "gtsender.h"
#include "gtcommencrypt.h"

/**
 * 超时等待时间 设置为35s
 */
int GtSender::_transTimeout = 35;
unsigned long GtSender::_terminalID = 0;
unsigned int GtSender::_userID = 0;

int GtSender::getSender() {
    int result = 0;
    int socketFd = -1;
    char connIP[128] = "127.0.0.1";
    unsigned short connPort = 15000;

    result = GtToolkitExt::tcpSocket(&socketFd);
    if (result != 0) {
        return result;
    }
    result = GtToolkitExt::tcpConnect(socketFd, connIP, connPort, 10);
    if (result != 0) {
        close(socketFd);
        return result;
    }
    return socketFd;
}

void GtSender::closeSender(int sender) {
    close(sender);
}

int GtSender::sendMessage(int transCode, unsigned char *inData, int inSize, unsigned char *outData,
                          int *outSize) {
    int result = 0;
    int socketFd = -1;

    socketFd = getSender();
    if (socketFd < 0) {
        GtError::localErrorString(socketFd, (char *) outData);
        *outSize = strlen((char *) outData);
        return socketFd;
    }
    result = writeAndRead(socketFd, transCode, inData, inSize, outData, outSize);
    if (result != 0) {
        if (result <= -10000) {
            GtError::localErrorString(result, (char *) outData);
            *outSize = strlen((char *) outData);
        }
    }
    //投注交易票数据处理
    if (transCode == 101200) {
        if (result == 0 || (result > -10000 && result <= -1000)) {
            clearLastTicketFile();
        }
    }
    if (transCode == 101999) {
        if (result == 0 || (result > -10000 && result <= -1000)) {
            clearLastTicketFile();
        }
    }
    closeSender(socketFd);
    return result;
}

int GtSender::writeAndRead(int socketFd, int transCode, unsigned char *inData, int inSize,
                           unsigned char *outData, int *outSize) {
    stMessage sendMsg;
    stMessage receivedMsg;
    int count = 0;
    int offset = 0;
    int result = 0;
    int i = 0;


    //数据打包
    memset(&sendMsg, 0, sizeof(stMessage));
    inPackage(transCode, inData, inSize, &sendMsg);
    //GtToolkitExt::logInfo(__FILE__, __LINE__, "%s", &sendMsg.strData[2]);
    //发送请求报文
    result = GtToolkitExt::writeN(socketFd, (void *) &sendMsg,
                                  sizeof(stMessageTag) + sendMsg.msgTag.ulDataSize);
    if (result != 0) {
        if (errno == SIGPIPE) {
            closeSender(socketFd);
        }
        GtToolkitExt::logError(__FILE__, __LINE__, "发送请求数据错误<%d>", result);
        return result;
    }
    //接收应答报文
    while (true) {
        memset(&receivedMsg, 0, sizeof(stMessage));
        result = GtToolkitExt::readN(socketFd, (void *) &receivedMsg.msgTag, sizeof(stMessageTag),
                                     _transTimeout);
        if (result != 0) {
            if (result == GtError::ERROR_CLOSED) {
                closeSender(socketFd);
            }
            GtToolkitExt::logError(__FILE__, __LINE__, "读取应答数据错误<%d>", result);
            return result;
        }
        //数据包大小超出范围出错处理
        if (receivedMsg.msgTag.ulDataSize >= SENDER_MTU) {
            count = receivedMsg.msgTag.ulDataSize / SENDER_MTU;
            offset = receivedMsg.msgTag.ulDataSize % SENDER_MTU;
            for (i = 0; i < count; i++) {
                result = GtToolkitExt::readN(socketFd, receivedMsg.strData, SENDER_MTU,
                                             _transTimeout);
                if (result != 0) {
                    if (result == GtError::ERROR_CLOSED) {
                        closeSender(socketFd);
                    }
                    GtToolkitExt::logError(__FILE__, __LINE__, "读取应答数据错误<%d>", result);
                    return result;
                }
            }
            if (offset > 0) {
                result = GtToolkitExt::readN(socketFd, receivedMsg.strData, offset, _transTimeout);
                if (result != 0) {
                    if (result == GtError::ERROR_CLOSED) {
                        closeSender(socketFd);
                    }
                    GtToolkitExt::logError(__FILE__, __LINE__, "读取应答数据错误<%d>", result);
                    return result;
                }
            }
            GtToolkitExt::logError(__FILE__, __LINE__, "读取应答数据错误<%d>", GtError::ERROR_READ_FAILED);
            return GtError::ERROR_READ_FAILED;
        }
        if (receivedMsg.msgTag.ulDataSize > 0) {
            result = GtToolkitExt::readN(socketFd, receivedMsg.strData,
                                         receivedMsg.msgTag.ulDataSize, _transTimeout);
            if (result != 0) {
                if (result == GtError::ERROR_CLOSED) {
                    closeSender(socketFd);
                }
                GtToolkitExt::logError(__FILE__, __LINE__, "读取应答数据错误<%d>", result);
                return result;
            }
        }
        //GtToolkitExt::logInfo(__FILE__, __LINE__, "%s", &receivedMsg.strData[2]);
        //writeMainTransLog(localCode, (char *)readData.strData);
        //数据包校验
        if (checkReceivedMessage(&receivedMsg)) {
            break;
        }
    }
    //数据解包
    result = outPackage(&receivedMsg, outData, outSize);
    if (result != 0) {
        return result;
    }
    return 0;
}

bool GtSender::checkReceivedMessage(stMessage *msg) {
    int result = 0;
    char tmpBuf[1024];
    unsigned long transSN = 0;
    unsigned long transCode = 0;
    long crc32 = 0;

    //验证流水号
    result = GtToolkitExt::parseNChar((char *) &msg->strData[2], tmpBuf, sizeof(tmpBuf),
                                      Gt::_delimiter1, 4);
    if (result != 0) {
        GtToolkitExt::logError(__FILE__, __LINE__, "流水号解析错误<%d>", result);
        return false;
    }
    transSN = atol(tmpBuf);
    if (transSN != msg->msgTag.ulTransSN) {
        GtToolkitExt::logError(__FILE__, __LINE__, "流水号校验错误");
        return false;
    }
    //验证CRC
    crc32 = GtEncrypt::crc32(msg->strData, msg->msgTag.ulDataSize);
    if (crc32 != msg->msgTag.lCRC) {
        GtToolkitExt::logError(__FILE__, __LINE__, "CRC校验错误");
        return false;
    }
    //验证交易码
    result = GtToolkitExt::parseNChar((char *) &msg->strData[2], tmpBuf, sizeof(tmpBuf),
                                      Gt::_delimiter1, 1);
    if (result != 0) {
        GtToolkitExt::logError(__FILE__, __LINE__, "交易码解析错误<%d>", result);
        return false;
    }
    transCode = atol(tmpBuf);
    if (transCode == 999999) {
        memset(tmpBuf, 0, sizeof(tmpBuf));
        result = GtToolkitExt::parseNChar((char *) &msg->strData[2], tmpBuf, sizeof(tmpBuf),
                                          Gt::_delimiter1, 6);
        if (result != 0) {
            GtToolkitExt::logError(__FILE__, __LINE__, "交易码解析错误<%d>", result);
            return false;
        }
        transCode = atol(tmpBuf);
        if (transCode != msg->msgTag.ulTransCode) {
            GtToolkitExt::logError(__FILE__, __LINE__, "交易码校验错误");
            return false;
        }
    } else {
        if (transCode != msg->msgTag.ulTransCode) {
            GtToolkitExt::logError(__FILE__, __LINE__, "交易码校验错误");
            return false;
        }
    }
    return true;
}

int GtSender::outPackage(stMessage *msg, unsigned char *outData, int *outSize) {
    int result = 0;
    char tmpBuf[2048];
    unsigned long transCode = 0;
    int errorCode = 0;

    //验证交易码
    result = GtToolkitExt::parseNChar((char *) &msg->strData[2], tmpBuf, sizeof(tmpBuf),
                                      Gt::_delimiter1, 1);
    if (result != 0) {
        return result;
    }
    transCode = atol(tmpBuf);
    if (transCode == msg->msgTag.ulTransCode) {
        result = GtToolkitExt::parseNCharIndex((char *) &msg->strData[2], Gt::_delimiter1, 5);
        if (result < 0) {
            return result;
        }
        memcpy(outData, &msg->strData[result + 1 + 2], msg->msgTag.ulDataSize - result - 1 - 2);
        *outSize = msg->msgTag.ulDataSize - result - 1 - 2;
        return 0;
    } else if (transCode == 999999) {
        memset(tmpBuf, 0, sizeof(tmpBuf));
        result = GtToolkitExt::parseNChar((char *) &msg->strData[2], tmpBuf, sizeof(tmpBuf),
                                          Gt::_delimiter1, 3);
        if (result != 0) {
            return false;
        }
        errorCode = atol(tmpBuf);
        memset(tmpBuf, 0, sizeof(tmpBuf));
        result = GtToolkitExt::parseNChar((char *) &msg->strData[2], tmpBuf, sizeof(tmpBuf),
                                          Gt::_delimiter1, 7);
        if (result != 0) {
            return false;
        }
        *outSize = sprintf((char *) outData, "%s<%d>", tmpBuf, errorCode);
        //strcpy((char *)outData, tmpBuf);
        //*outSize = strlen(tmpBuf);
        return errorCode;
    }
    return 0;
}

void GtSender::inPackage(int transCode, unsigned char *inData, int inSize, stMessage *msg) {
    int length = 0;
    char tmpBuf[1024];
    unsigned long transSN = 0;

    if (transCode == 100000) {
        memset(tmpBuf, 0, sizeof(tmpBuf));
        GtToolkitExt::parseNChar((char *) inData, tmpBuf, sizeof(tmpBuf), Gt::_delimiter1, 3);
        _terminalID = atol(tmpBuf);
        memset(tmpBuf, 0, sizeof(tmpBuf));
        GtToolkitExt::parseNChar((char *) inData, tmpBuf, sizeof(tmpBuf), Gt::_delimiter1, 4);
        _userID = atol(tmpBuf);
    }
    transSN = GtToolkitExt::uniqueSerialNumber();
    length = sprintf((char *) &msg->strData[2], "%d%c%d%c%lu%c%lu%c%d%c", transCode,
                     Gt::_delimiter1,
                     GtCommEncrypt::instance()->getCommEncryptType(), Gt::_delimiter1,
                     transSN, Gt::_delimiter1,
                     _terminalID, Gt::_delimiter1,
                     _userID, Gt::_delimiter1);
    if (inSize > 0) {
        memcpy(&msg->strData[2 + length], inData, inSize);
    }
    msg->msgTag.ulType = 1;
    msg->msgTag.ulVersion = 1;
    msg->msgTag.ulTransSN = transSN;
    msg->msgTag.ulTransCode = transCode;
    msg->msgTag.ulDataSize = length + inSize;
    msg->strData[0] = msg->msgTag.ulDataSize / 256;
    msg->strData[1] = msg->msgTag.ulDataSize % 256;
    msg->msgTag.ulDataSize += 2;
    msg->msgTag.lCRC = GtEncrypt::crc32(msg->strData, msg->msgTag.ulDataSize);
    //投注交易保存票数据
    if (transCode == 101200) {
        stLastTicket lastTicket;
        memset(&lastTicket, 0, sizeof(stLastTicket));
        lastTicket.ulKey = 0;
        memset(tmpBuf, 0, sizeof(tmpBuf));
        GtToolkitExt::parseNChar((char *) inData, tmpBuf, sizeof(tmpBuf), Gt::_delimiter1, 1);
        lastTicket.unGameID = atol(tmpBuf);
        memset(tmpBuf, 0, sizeof(tmpBuf));
        GtToolkitExt::parseNChar((char *) inData, tmpBuf, sizeof(tmpBuf), Gt::_delimiter1, 2);
        lastTicket.ulIssue = atol(tmpBuf);
        memset(tmpBuf, 0, sizeof(tmpBuf));
        GtToolkitExt::parseNChar((char *) inData, tmpBuf, sizeof(tmpBuf), Gt::_delimiter1, 3);
        lastTicket.ulTicketSN = atol(tmpBuf);
        memset(tmpBuf, 0, sizeof(tmpBuf));
        GtToolkitExt::parseNChar((char *) inData, tmpBuf, sizeof(tmpBuf), Gt::_delimiter1, 5);
        lastTicket.ulKey = atol(tmpBuf);
        lastTicket.ulTerminalID = _terminalID;
        lastTicket.ulFrontSN = transSN;
        writeLastTicketFile(&lastTicket);
    }
}

/************************************************************
*功能：保存最近一张票数据文件
*输入：lastTicket=票数据结构
*输出：无
*返回：!=0错误
*/
int GtSender::writeLastTicketFile(stLastTicket *lastTicket) {
    char path[512];
    int result = 0;

    memset(path, 0, sizeof(path));
    Gt::instance()->getLastTicketDatFile(path);
    result = GtToolkitExt::writeSyncFile(path, lastTicket, sizeof(stLastTicket));
    if (result != 0) {
        return GtError::ERROR_WRITE_LAST_TICKET;
    }
    return 0;
}

/************************************************************
*功能：删除最近一张票数据文件
*输入：无
*输出：无
*返回：!=0错误
*/
int GtSender::clearLastTicketFile() {
    char path[512];
    int result = 0;

    memset(path, 0, sizeof(path));
    Gt::instance()->getLastTicketDatFile(path);
    result = GtToolkitExt::truncateSyncIOFile(path);
    if (result != 0) {
        return GtError::ERROR_CLEAR_LAST_TICKET;
    }
    unlink(path);
    result = GtToolkitExt::getFileSize(path);
    if (result > 0) {
        return GtError::ERROR_CLEAR_LAST_TICKET;
    }
    return 0;
}

/************************************************************
*功能：读取最近一张票数据文件
*输入：无
*输出：lastTicket=票数据结构
*返回：!=0错误
*/
int GtSender::readLastTicketFile(stLastTicket *lastTicket) {
    char path[512];
    int result = 0;

    memset(path, 0, sizeof(path));
    Gt::instance()->getLastTicketDatFile(path);
    result = GtToolkitExt::readFile(path, lastTicket, sizeof(stLastTicket));
    if (result != 0) {
        return GtError::ERROR_READ_LAST_TICKET;
    }
    return 0;
}

/************************************************************
*功能：最近一张票数据文件是否存在
*输入：无
*输出：无
*返回：true,false
*/
bool GtSender::lastTicketFileExist() {
    char path[512];
    int result = 0;

    memset(path, 0, sizeof(path));
    Gt::instance()->getLastTicketDatFile(path);
    result = GtToolkitExt::getFileSize(path);
    if (result > 0) {
        return true;
    } else {
        return false;
    }
}
