#ifdef SBKDLL

#include "DataProcess/tools.h"
#include "DataProcess/rollback.h"
#include <qwinwidget.h>

#include <QMessageBox>
#include <QDateTime>
#include <windows.h>
#include <QFont>
#include <QFontDatabase>
#include "control.h"
#include "global.h"
#include "QsLog.h"
#include "requestmodel.h"
#include "fmtool.h"
#include "rspfactory.h"
#include "fmp_settings.h"
#include "version.h"

#include <QDir>
#include <QtMessageHandler>
#include <QFile>
#include <QFileInfo>
#include <QDateTime>
#include <QTextStream>

#define QMESLOGNAME "C:/freemud/fmclient/log/QMessageHandleLog"
#define QMESLOGNAMEBAK "C:/freemud/fmclient/log/QMessageHandleLogBak"
#define QMESMAXFILESIZE 4   //单位 M;

EXTERN_C IMAGE_DOS_HEADER __ImageBase;

static void fileSizeLimitProcess() {
    QFile     file(QMESLOGNAME);
    QFile     fileBak(QMESLOGNAMEBAK);
    QFileInfo fileinfo(QMESLOGNAME);
    if(fileinfo.size()/1024 >= QMESMAXFILESIZE*1024){
        if(fileBak.exists()) {
            fileBak.remove();
        }
        bool renameRet = file.rename(QMESLOGNAMEBAK);
        Q_UNUSED(renameRet);
        /*** 一次备份不成功，等待程序初次启动在进行备份转移 ***/
    }
}

static void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    // 加锁 :防止死锁:注释加锁机制;
    // static QMutex mutex; mutex.lock();
    QByteArray localMsg = msg.toLocal8Bit();
    QString strMsg("");
    switch(type)
    {
    case QtDebugMsg:
        strMsg = QString("Debug:");
        break;
    case QtWarningMsg:
        strMsg = QString("Warning:");
        break;
    case QtCriticalMsg:
        strMsg = QString("Critical:");
        break;
    case QtFatalMsg:
        strMsg = QString("Fatal:");
        break;
    }
    // 设置输出信息格式
    QString strDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");
    QString strMessage = QString("LogLevel:%1 Message:%2 File:%3  Line:%4  Function:%5  DateTime:%6")
            .arg(strMsg).arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function).arg(strDateTime);

    // 输出信息至文件中（读写、追加形式） c:\freemud\fmclient\log\QMessageHandleLog
    QFile file(QMESLOGNAME);
    fileSizeLimitProcess();
    file.open(QIODevice::ReadWrite | QIODevice::Append);
    QTextStream stream(&file);
    stream << strMessage << "\r\n";
    file.flush();
    file.close();
    // 解锁 :防止死锁:注释加锁机制;
    // mutex.unlock();
}

static void InitLogger()
{

    char path[MAX_PATH] = {0};
    ToolS::GetProcPath(path);

    FMPSettings setting;
    QString logPath = setting.GetValue(CONFIG_LOG_PATH, QString(path)+"/log").toString();
    QString logName = setting.GetValue(CONFIG_LOG_NAME, "sbuxpay.txt").toString();
    QsLogging::Level logLevel = (QsLogging::Level)setting.GetValue(CONFIG_LOG_LEVEL, 0).toInt();
    if(logLevel < QsLogging::TraceLevel || logLevel > QsLogging::OffLevel) {
        logLevel = QsLogging::TraceLevel;
    }
    int logSize = setting.GetValue(CONFIG_LOG_SIZE, 1).toInt();
    int logCount = setting.GetValue(CONFIG_LOG_COUNT, 20).toInt();

    QDir logDir(logPath);
    if(!logDir.exists()) {
        logDir.mkpath(logDir.absolutePath());
    }
    QString logFilePath = logDir.absolutePath()+'/'+logName;
    QsLogging::Logger& logger = QsLogging::Logger::instance();
    logger.setLoggingLevel(logLevel);

    /* 配置输出定向器 */
    QsLogging::DestinationPtr fileDestination(QsLogging::DestinationFactory::MakeFileDestination(
    logFilePath,
    QsLogging::EnableLogRotation, QsLogging::MaxSizeBytes(1024*1024*logSize),
                                  QsLogging::MaxOldLogCount(logCount)));
    logger.addDestination(fileDestination);

    QsLogging::DestinationPtr consleDest(QsLogging::DestinationFactory::MakeDebugOutputDestination());
    logger.addDestination(consleDest);
}

static bool SetEnvironmentVar(QString &path, QString &configPath)
{
    //外层的DLL包装类添加后的环境变量没有生效；顾需要本DLL在次添加;
    QLOG_INFO()<< "<<==============SetEnvironmentVar begin===============>>";
    char mod[MAX_PATH] = { 0 };
    bool setEnvRet = false;

    GetModuleFileNameA((HMODULE)&__ImageBase, mod, MAX_PATH);
    char *ch = strrchr(mod,'\\');
    if (ch++) {
        *ch = '\0';
    }
    path = QString::fromLocal8Bit(mod);
    path = path.replace("\\", "/");
    QApplication::addLibraryPath(path);
    FMPSettings setting;
    configPath = setting.GetValue(CONFIG_ALL_PATH, path).toString();
    configPath = configPath.replace("\\", "/");
    //测试替换成功;
    QLOG_INFO()<< "SetEnvironmentVar:: configPath: " << configPath <<" Path: " <<path<<" MoudlePath:"<<mod;
    QApplication::addLibraryPath(configPath);

    QByteArray val = qgetenv("PATH");
    QByteArray valNew = "";
    if( val.contains(mod) ) {
        setEnvRet = true;
        QLOG_INFO()<< "SetEnvironmentVar:: EnvironmentVar Had Include Path: " << mod;
    } else {
        valNew += val;
        valNew += ";";
        valNew += mod;
        setEnvRet = qputenv("PATH", valNew);
        QLOG_INFO()<< "SetEnvironmentVar:: New Set Environment Ret: " << setEnvRet <<" ErrorNum:"<<GetLastError();
    }
    QLOG_INFO()<< "<<==============SetEnvironmentVar end===============>>";
    return  setEnvRet;
}

BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpvReserved*/ )
{
    static bool ownApplication = FALSE;

    if ( dwReason == DLL_PROCESS_ATTACH ) {
        InitLogger();

        int setEnvRetryNum = 10;
        bool SetEnvRet = false;
        QString path="", configPath="";

        bool firstSetEnvRet = SetEnvironmentVar(path,configPath);
        SetEnvRet = firstSetEnvRet;
        // 初次设置环境环境变量失败后:重试上限10次;
        while(!SetEnvRet && setEnvRetryNum){
            setEnvRetryNum--;
            SetEnvRet = SetEnvironmentVar(path,configPath);
            QLOG_INFO() << "Retry SetEnvironmentVar() Num: " << (10 - setEnvRetryNum) <<" SetEnvRet: "<<SetEnvRet;
        }
        QLOG_INFO() << "Library Paths:  " << QApplication::libraryPaths()
                 <<" Config Dll Path: "<< configPath <<" firstSetEnvRet: "<<firstSetEnvRet
                <<" Retry SetEnv Num:"<<(10 - setEnvRetryNum);

        QLOG_INFO() << QString("Program run. Version: %1.%2.%3.%4").arg(VER_MAJOR).arg(VER_MINOR).arg(VER_REVISION).arg(VER_BUILD);

        // 安装消息处理程序
        qInstallMessageHandler(myMessageOutput);

        ownApplication = QMfcApp::pluginInstance( hInstance );
        //防止环境变量没有对Qt程序实例生效,再次设置环境变量;
        SetEnvRet = SetEnvironmentVar(path,configPath);
        QLOG_INFO() << "LastOne SetEnvironmentVar() : SetEnvRet: "<<SetEnvRet <<"EnvPath: " << qgetenv("PATH");

        QFontDatabase::addApplicationFont(path + "msyh.ttf");
        QFont ft("Microsoft YaHei UI Light");
        qApp->setFont(ft);
    }
    if ( dwReason == DLL_PROCESS_DETACH && ownApplication )
        delete qApp;

    return TRUE;
}

extern "C" __declspec(dllexport) void Start(const char *indata, char *outdata)
{
    HWND parent = GetDesktopWindow();
    QWinWidget win( parent );

    Control control(&win);
    control.Start(indata, outdata);

    static RollBack rollback;
    if(!rollback.isRunning())
        rollback.start();
}


#else

#ifdef FM_TEST

#include "control.h"
#include "global.h"
#include "QsLog.h"
#include "requestmodel.h"
#include "fmtool.h"
#include "rspfactory.h"
#include <QDir>
#include <QApplication>
#include "DataProcess/rollback.h"
#include <QStringList>
#include "DataProcess/dataprocess.h"
#include "DataProcess/cretopt.h"

static RollBack rollback;

void TestSetString() {
    AlipayResponse repon;
    FMTool::SetString(repon.ResponseMsg, 40, QString::fromLocal8Bit("sb"));
}

void TestSetPinter() {
     AlipayResponse repon;
    QJsonObject obj, json;
    obj.insert("print", "dasdas");
    json.insert("ext", obj);
    RspFactory::SetPinter(repon, json);
    qDebug() << "lalal";
}


typedef int (* GetValue) (char *, char *);
typedef int (__stdcall * GetRSACret)(int ,const char *,const char *);

void TestDllWapper() {
    QLibrary lib(qApp->applicationDirPath() + "/" + "FreemudWrapper.dll");
    if(lib.load()) {
        GetValue getvalue = (GetValue)lib.resolve("_GetValue@8");
        GetRSACret getrsacret = (GetRSACret)lib.resolve("_GetRSACret@12");
        qDebug() << getvalue;
        qDebug() << getrsacret;
        int j = -1;
        char t1[25600] = {0};
        char t2[25600] = {0};
        getvalue(t1, t2);
        qDebug() << j;
        qDebug() << t1;
        qDebug() << t2;
    } else
        qDebug() << "load error";

}

void TestDllFmclient() {
    QLibrary lib(qApp->applicationDirPath() + "/" + "test02.dll");
    qDebug() << qApp->applicationDirPath() + "/" + "test02.dll";

    if(lib.load()) {
        GetValue getvalue = (GetValue)lib.resolve("GetValue");
        GetRSACret getrsacret = (GetRSACret)lib.resolve("_GetRSACret@12");
        qDebug() << getvalue;
        qDebug() << getrsacret;
        int j = -1;
        getrsacret(1 , "1314", "2678");
        qDebug() << j;
    }

}


void TestDataProcess() {
    QJsonObject json;
    QJsonObject obj;

    json.insert("awqwe", 2);
    json.insert("Sklhfwj", "hello");
    json.insert("oiueqw","");
    json.insert("sign","jeqweqwje287398217");
    obj.insert("ldd", "hahahah");
    json.insert("lcd", obj);

    qDebug() << json;
    QStringList list;
    DataProcess::GetJsonKeyArray(list, json);
    qDebug() << "not sort" << list;
    DataProcess::SortString(list);
    qDebug() << "sort" << list;
    QString value;
    DataProcess::GetValueFromJson(list, json, value);
    qDebug() << value;
}

void TestCret()
{
    QJsonObject json;
    QJsonObject obj;
    QString sign;

    json.insert("awqwe", 2);
    json.insert("Sklhfwj", "hello");
    json.insert("oiueqw","");
    json.insert("sign","jeqweqwje287398217");
    obj.insert("ldd", "hahahah");
    json.insert("lcd", obj);
    qDebug() << json;
    CretOperate::GetSign(json, sign);
    qDebug() << json;
}


int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    QString logDir = QString("%1/log").arg(QApplication::applicationDirPath());
    QDir().mkdir(logDir);
    QsLogging::Logger& logger = QsLogging::Logger::instance();
    logger.setLoggingLevel(QsLogging::TraceLevel);
    QString str = qApp->applicationDirPath() + "/log/mcduncompress.txt";

    /* 配置输出定向器 */
    QsLogging::DestinationPtr fileDestination(QsLogging::DestinationFactory::MakeFileDestination(
    str,
    QsLogging::EnableLogRotation, QsLogging::MaxSizeBytes(1024*1024),
                                  QsLogging::MaxOldLogCount(5)));
    logger.addDestination(fileDestination);

    QsLogging::DestinationPtr consleDest(QsLogging::DestinationFactory::MakeDebugOutputDestination());
    logger.addDestination(consleDest);

    TestDataProcess();
    TestCret();

    qDebug() << "1212367123";

    AlipayRequest req;

    FMTool::SetString(req.BusinessDay, 8 , QString("20170909"));
    FMTool::SetString(req.TransType, 2 , QString("30"));
    FMTool::SetString(req.PlatNo, 4, QString("1443"));
    FMTool::SetString(req.TransTime, 6, QString("130301"));
    FMTool::SetString(req.StoreNo, 20 , QString("17607"));
    FMTool::SetString(req.DeviceNo, 6 , QString("1"));
    FMTool::SetString(req.CashierNo, 6 , QString("0123"));
    FMTool::SetString(req.CashTraceNo, 6 , QString("16723"));
    FMTool::SetString(req.OriginTrace, 64 , QString(""));
    FMTool::SetString(req.Amount, 12, QString("1"));
    FMTool::SetString(req.Reserved1, 48 , QString("1367623098735894422"));
    req.item_line_qty[0] = '2';
    req.item_line_qty[1] = ' ';

    struct product{
        char productID[8]; //商品id
        char buyCount[4]; //购买数量
        char unitPrice[8]; //单件商品价格
        char isCombo[1]; //默认为0
        char isNonsale[1]; //(废弃)
        char productName[20]; //商品名字
    };

    for(int i = 0; i < 99; ++i) {
        struct product *pro = (struct product *)req.item_information[i];
        FMTool::SetString(pro->productID, 8,QString::number(i+1));
        FMTool::SetString(pro->buyCount, 4,QString::number(i+1));
        FMTool::SetString(pro->unitPrice, 8,QString::number(i+1));
        FMTool::SetString(pro->isCombo, 1,QString::number(i%2));
        FMTool::SetString(pro->isNonsale, 1,QString::number(i+1));
        FMTool::SetString(pro->productName, 20,QString::fromLocal8Bit("asdasdasd"));
    }

    char as[MAX_BUF_LEN] = {0};
    memcpy(as, &req, sizeof(struct AlipayRequest));
    Control control;
    rollback.start();
    //char as[] = "ak10dh171300000000000    *#dhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh";
    char b[MAX_BUF_LEN] = {0};
    char spccIn[MAX_BUF_LEN] = "{\"reqType\":352,\"storeId\":\"1713\",\"code\":\"1212121\", \"stationId\":\"1\",\"partnerId\":1438,\"operatorId\":\"0123\",\"transId\":301439,\"transAmount\":1,\"partnerOrderId\":\"201709280001\",\"businessDate\":\"20170830\"}";
    control.Start(spccIn, b);
    return a.exec();
}

#endif //! FM_TEST

#endif
