/********************
 * 流程控制
 * *****************/

#ifndef FLOWCONTROL_H
#define FLOWCONTROL_H

//#include <QObject>
#include "Network/billSocket.h"
#include "Model/orderObject.h"
#include "Model/dishesObject.h"
#include "LocalServer/localHttpServer.h"
#include "alertForm.h"
#include <WinSock.h>
#include <QMap>
#include <JQHttpServer.h>
#include <QMutex>
#include <QDateTime>
#include <QJsonArray>
#include <QTimer>
#include <QPair>
#include <QSemaphore>

class FlowControl : public QObject
{
    Q_OBJECT
public:
    static FlowControl& GetInstance();

    /* 功能:获取目前插件FC 核心数据;
     * 参数: 1. 是否登录成功; 2.门店号; 3.PosPluginIp; 4.PosPlugin Port;
     * 返回: Void;
     * */
    void _GetFcMajorInfo(bool &loginResult, bool &openTcpChannel, QString &storeId, QString &posIp, QString &posHostName, QString &posWorkStationNum);


    /* 功能:获取收银员ID
     * 参数:NULL
     * 返回:是否成功
     * */
    QString _GetCashierId();


    /* 功能:获取收银员Name
     * 参数:NULL
     * 返回:是否成功
     * */
    QString _GetCashierName();

    /* 功能:判断SIM有效订单队列list 是否为空；
     * 参数:NULL
     * 返回:SIM有效订单队列是否为空;
     * */
    bool _SimValidOrdersListIsEmpty();

    //QStringList& _GetSimValidOrdersList();

private:
    FlowControl();
    FlowControl(FlowControl const&);
    FlowControl& operator=(FlowControl const&);

    typedef struct TOPULL_ORDER
    {
        int pageSize;
        int pageNumber;
        QString channel;
        QString orderId;
        int pullErrorCount;
        QString callBackUrl;
        bool  skipPrint;
        QJsonObject pushOptions;

    }PullOrderInfo;

    typedef struct ORDER_OPERATION
    {
        int operation;//1:接单,0:取消订单
        int result;//1:成功,0:失败
        QString orderId;

    }OrderOperation;

    //存放向OMS汇报的结构体: 订单入机POS的情况;
    typedef struct REPORTOMS_ORDERRECORD
    {
        QString orderNo;  //订单号
        QString channel;  //订单渠道
        QString type;     //订单状态:[3:正向单；6:退货单; 9:POS机系统级别错误; 0:未知订单状态]
        QString status;   //订单入机状态:[1:成功; 2:失败]
        QString opUser;   //当前收银员;
        QString recordDate; //入机成功、入机失败的时间[时间格式: 2018-10-09 10:41:22]
        QString storeId;    //门店编号
        QString remark;     //备注:入机出错信息
        QString checkNo;    //小票号:入机成功时的小票号;
        QString failCode;    // 入机/存储 错误码 (成功时都给 "");
        QString pluginVersion;  //该订单入机后, 汇报给OMS对应程序的版本号;
        int     reqResult;  //向OMS请求汇报结果;

    }RepOMSRecordOrderInfo;

    //定义门店的营业状态;
    typedef enum {
        UNKNOWN=0,OPEN=1,CLOSE=2 /*0:未知；1:开店；2:关店*/
    }StoreStatus;

private:
    // 门店信息
    QString m_storeId;
    QString m_ipAddress = "";      // 门店POS的 IP 地址
    QString m_ipPortAddress;  // 门店POS的 IP+端口 地址
    QString m_posHostName;   // Pos 主机名;
    QString m_posMacAddress;  // Pos Mac地址;
    QString m_posWorkstationNum;  // Pos 工作站编号
    QString m_pmsMachineNo;   // 标志PMS 系统插件程序所在机器编号
    QString m_password;
    QString m_puginVersionComments;
    QString m_posId;
    QString m_cashierId;
    QString m_cashierName;
    QDateTime m_bDate;
    QString m_storeName;
    int m_eleStoreStatus;
    int m_mopStoreStatus;
    int m_modStoreStatus;
    int m_mtModStoreStatus;
    int m_existNoAckNotice;
    bool m_bLastHeartIsError;
    int m_orderCount;
    int m_o2ofulfillmentOrderCount;
    //订单清除定时器
    QTimer *m_clearTimer;
    QTimer *m_heartTimer;
    QTimer *m_pullTimer;
    QTimer *m_reportOMSReocrdOrderTimer;
    QTimer *m_loginTimer;
    QTimer *m_remindCasherBlinkFloatTimer;  //插件程序收到外卖订单后，需要一致提醒店员[直到此外卖订单被全部录入到POS系统]
    QTimer *m_notifyPmsPullTimer;
    QTimer *m_notifyPmsUpdateTimer;
    //QTimer *m_cyclePullAllOrderTimer;     //由于定时器是为了周期性获取全部订单; 原因: PmsPlugin  set StoreServiceCenter; aviod missing Orders;
    //已经通过心跳返回当天有效订单数据进行 漏单检查，故无需 周期性获取订单列表;
    // 网络通信
    BillSocket *m_loginSocket;
    BillSocket *m_pullOrderSocket;
    BillSocket *m_reportOMSRecordOrderSocket;
    BillSocket *m_pullOrderListSocket;
    BillSocket *m_procOrderSocket;
    BillSocket *m_pullDishesSocket;
    // FM外卖插件维护的有效订单容器
    QMap<QString, OrderObject*> m_FmOrdersMap;
    // 是否第一次获取到门店信息
    bool m_bFirstRecvInfo;
    bool m_bLoginResult;
    int m_loginErrorCount;
    int m_sendHeartErrorCount;
    bool m_bCreateSelfCheckOrderError;
    bool m_openTcpChannel;
    bool m_bOperateResult;
    // 标记目前悬浮框是否 锁住状态[false:悬浮框解锁状态; true:悬浮框锁住状态]；
    bool m_bFloatFromLockSt;
    // HttpServer
    LocalHttpServer* localHttpServer;
    // QtRedis Operat Process

    QMap<QString,  QMultiMap<QString, dishesObject> >m_dishesMap;
    //等待Simphony拉取的有效订单队列list[orderId]
    QStringList m_simValidOrdersList;
    //等待更新PMS 订单数据的有效订单队列list[orderId]
    QStringList m_waitUpdateOrderList;
    //订单号与pos短号映射:[可能同时存在两种状态:1:新单记录；2:退单记录；但是小票号就存一个;]
    QMap<QString,QString> m_orderIdToPosCheckNoMap;
    //记录当前订单操作
    QMap<QString, int> m_orderOperatePair;
    //订单拉取记录
    QList<PullOrderInfo*> m_orderPullList;
    QMutex m_PullOrderDataMutex;

    //向OMS汇报订单的POS入机情况 队列;
    QList<RepOMSRecordOrderInfo*> m_orderRecordRepOMSList;
    QMutex m_RepOMSRecordOrderMutex;
    //订单操作互斥信号 QSemaphore semaphore;
    QMutex m_OrderEntryMutex;

    //  PMS 同步订单列表的操作互斥信号;
    QMutex m_OrderUpdateMutex;

    //新增三个bool变量用来标识 程序初始化时，两个数据库中的三张表是否能够连接正常；
    bool m_initSimProcOrderDBRet;
    bool m_initPrintSumBillPosDBRet;
    bool m_initGetAuthPosDBRet;
    bool m_initPmsGetStoreConfigDBRet;
    bool m_initPmsOrdersDataRet;
    bool m_initPmsRedisRet;

    // 新增: 记录OMS备用服务的 CallBackUrl 地址; 便于OMS服务异常时,具备热切换功能: 登录 + 订单列表 + 心跳 + 自检单;
    QString m_serviceCallBackUrl;

signals:
    // 发送信号给自己 做登陆
    // void doLogin();

    // http门店POS登录成功后 发送信号给  SocketCommunicate;
    void doLoginSuccess(bool loginResult,bool openTcpFlag, QString &storeId, QString &posIp, QString &posHostName, QString &posWorkStationNum);


    /* 功能:隐藏通知窗口
     * 参数:NULL
     * 返回:NULL
     * */
    void hideAlert();

    /* 功能:显示通知窗口
     * 参数:[1]窗口类型[2]显示信息
     * 返回:NULL
     * */
    void showAlert(AlertForm::Type type, const QString& msg);

    /* 功能:隐藏主界面显示悬浮窗口
     * 参数:[1]窗口类型[2]显示信息
     * 返回:NULL
     * */
    void doHideMainShowFloatFrom();

    /* 功能:通知 锁住 悬浮窗
     * 参数:NULL
     * 返回:NULL
     * */
    void doLockFloatForm();

    /* 功能:通知 解锁 悬浮窗
     * 参数:NULL
     * 返回:NULL
     * */
    void doUnLockFloatFrom();

    /* 功能:通知 更新门店 三个渠道的开关店状态;
     * 参数:1 [ele开关店状态] 2[MOD开关店状态] 3[MOP开关店状态]
     * 返回:Null
     * */
    void doUpdateStoreStatus(int eleStoreStatus, int modStoreStatus, int mopStoreStatus, int mtStoreStatus, int existNoAckNotice);


    /* 功能:设置主界面门店信息
     * 参数:[1]门店号
     * 返回:NULL
     * */
    void setStoreInfo(const QString& storeId);
    /* 功能:设置主界收银员信息
     * 参数:[1]收银员信息
     * 返回:NULL
     * */
    void setCashierInfo(const QString& cashierInfo);
    /* 功能:设置门店营业状态
     * 参数:[1]营业状态
     * 返回:NULL
     * */
    void setOpeStatus(const QString& status);
    /* 功能:设置门店网络状态
     * 参数:[1]网络状态
     * 返回:NULL
     * */
    void setNetStatus(const QString& status);

    /* 功能:更改订单显示表
     * 参数:[1]订单对象[2]旧订单的状态
     * 返回:NULL
     * */
    void changeOrderStatus(OrderObject* orderObject, int oldStatus=-100);

    /* 功能:显示订单详情界面
     * 参数:[1]收银员信息
     * 返回:NULL
     * */
    void showOrderDetails(OrderObject* orderObject);
    /* 功能:显示订单搜索结果
     * 参数:[1]搜索结果
     * 返回:NULL
     * */
    void showSearchOrderResult(const QMap<QString,QString>& orderMap);

    // 通知菜品管理界面初始化菜品信息
    void iniDishesData(QMap< QString, QMultiMap<QString, dishesObject> >);

    // 通知门店营业管理界面初始化信息
    void initChannelsData(QStringList);


    // 通知菜品管理界面操作成功刷新界面 [1]菜品所属分类 [2]具体菜品
    void processDishiesSuccssful(QString, QMap<QString, int>);

    // 通知营业状态管理界面操作成功
    void setStoreOperatingStatusFinsh(QString);

    /* 功能:通知界面清空订单
     * 参数:[1]订单号[2]订单状态
     * 返回:NULL
     * */
    void clearorder(const QString& orderId,const int& oldstatus);
    /* 功能:通知界面展示日结
     * 参数:[1]日结数据JSON
     * 返回:NULL
     * */
    void showDailyReportData(QJsonObject);


    /* 功能:通知开始提醒
     * 参数:[1]提醒类型
     * 返回:NULL
     * */
    void startRemind(int);

    void setStoreStatusChanged(QJsonArray);

    void doConfirmOrder(const QString& orderId);
    void doRefundOrder(const QString& orderId, int reasonCode, const QString &reason, const QString & dishesListString);
    void doStartOperateTimer();

public slots:

    void _TestRedis();

    void _TestInsertOrderData();

    bool _AppendOrderInfo2Redis(const OrderObject* orderObject);

    bool _GetStoreInfo();

    /* 功能:登录前初始化数据;
     * 参数:NULL
     * 返回:NULL
     * */
    void _InitDataBeforeLogin();

    /* 功能:登录
     * 参数:NULL
     * 返回:是否成功
     * */
    bool _Login();
    /* 功能:拉取订单
     * 参数:[1]订单编号
     * 返回:是否成功
     * */
    void _PullOrderData();
    /* 功能:拉取指定订单
     * 参数:[1]订单编号
     * 返回:是否成功
     * */
    bool _PullOrderDetail( const QString& orderId, const QString& channel, const QString& callBackUrl, const bool& skipPrint = false, const QJsonObject& pushOptins = QJsonObject(),
                           const bool& skipErrorDisplay = false );
    /* 功能:拉取订单
     * 参数:NULL
     * 返回:是否成功
     * */
    bool _PullOrderList(const int &pageSize, const int &pageNo, const QString &callBackUrl);
    /* 功能:发送心跳
     * 参数:NULL
     * 返回:是否成功
     * */
    bool _SendHeart();
    /* 功能:确认订单
     * 参数:[1]订单编号[2]配送员信息
     * 返回:是否成功
     * */
    bool _ConfirmOrder(const QString& orderId);

    /* 功能:送出订单
     * 参数:[1]订单编号
     * 返回:是否成功
     * */
    bool _SendOrder(const QString& orderId);
    /* 功能:完成订单
     * 参数:NULL
     * 返回:是否成功
     * */
    bool _CompleteOrder(const QString& orderId);

    /* 功能:退单
     * 参数:NULL
     * 返回:是否成功
     * */
    bool _RefundOrder(const QString& orderId, int reasonCode, const QString &reason,
                      const QString& dishesListString);

    /* 功能:更新数据库中订单状态后且 push Redis 成功后添加汇报list;
     * 参数:[1] 订单对象指针;
     * 返回:NULL
     * */
    void _AddOrderInfo2ReportList(const OrderObject* orderObject,const QString& operatStatus,
                                  const QString& remarkMessage);

    /* 功能:定时触发向OMS 汇报本地POS订单的入机情况;
     * 参数:NULL
     * 返回:NULL
     * */
    void _ReportOMSRecordOrderInfo();

    /* 功能:获取Json对象的字符
     * 参数:NULL
     * 返回:Json字符串
     * */
    QString _GetJsonStr(const QJsonObject& json);
    /* 功能:获取Http返回Json数据
     * 参数:NULL
     * 返回:Json对象
     * */
    /**
    *功能:定时清空订单Map里两天前的订单
    *参数:无
    *返回:无
    **/
    void _CrondClearExpireOrder();

    // 单位转换
    QString _Penny2Dollar(int penny);

    void _GetIpAddress();
    void _AddOrderPull( const QString& orderId=0, const QString& channel=0, const QString& callBackUrl="", const int& pageNumber=1, const int& pageSize=30 );
    // 避免获取较多历史订单的同时，OMS又有推单过来，导致死锁;
    bool _TryAddOrderPull(const QString &orderId=0, const QString &channel=0, const QString &callBackUrl="", const int &pageNumber=1, const int &pageSize=30);

    //点击屏幕指定区域
    void _ClickOMSAssignArea();
    void _ClickToLogin();
    void _NotifyPmsPullOrder();
    void _NotifyPmsUpdateOrder();
    void _NotifyCyclePullAllOrder();
    void _RemindCasherBlinkFloatForm();
    void _OrderAnalysis(const QJsonObject &jsonObject);

    //减轻压测插件时: 插件崩溃(STACK_OVERFLOW_Qt5Gui!std::_Mutex::_Mutex+266) + POS收银系统奔溃（POS机屏幕点击频率过高 + 总次数过高 导致崩溃）
    void _SmartTriggerClickPosBtn(const bool bTimerTrigger = false);


public slots:
    /* 功能:获取到新的门店信息
     * 参数:[1]操作员ID[2]POS机ID
     *      [3]门店ID[4]营业日
     * 返回:NULL
     * */
    void onGetNewStoreInfo();

    /* 功能:处理订单
     * 参数:[1]操作动作名[2]订单编号[3]配送员姓名
     * 返回:NULL
     * */
    void onProcessOrder(const QString& operation, const QString& orderId);

    /* 功能: 接受长连接推送消息数据
     * 参数:[1]字节数组格式 报文 [2] 消息类型ID
     * 返回: 处理成功;
     * */
    bool onRecvSocketPushedMsg(QByteArray &msgData, int & actionId);

    /* 功能:获取订单详情
     * 参数:NULL
     * 返回:NULL
     * */
    void onGetOrderDetails(const QString &orderId);

    /* 功能:获取 EC-MOP 订单详情
     * 参数: OrderId, Channel
     * 返回:NULL
     * */
    void onGetEcMopOrderDetails(const QString &orderId, const QString &channel);


    /* 功能:搜索订单
     * 参数:[1]搜索内容
     * 返回:NULL
     * */
    void onSerachOrder(const QString& text);

    /* 功能:拒绝订单;
     * 参数:[1]订单号 [] [] [] []
     * 返回:NULL
     * */
    void onProcessRejectOrder(const QString& orderId, const int& reasonCode,const QString &reason);

    /* 功能:作废订单;
     * 参数:[1]订单号 [] [] [] []
     * 返回:NULL
     * */
    void onProcessRepealOrder(const QString& orderId, const int& reasonCode,const QString &reason,const QString& dishesListString);

    /* 功能:重新向POS录入外卖订单;
     * 参数:[1]订单号
     * 返回:NULL
     * */
    void onProcessRetryInputOrder(const QString& orderId);

    /* 功能:获取门店营业状态
     * 参数:NULL
     * 返回:NULL
     * */
    void onGetBusinessStatus();

    /* 功能:获取OMS服务端全部订单
     * 参数:NULL
     * 返回:NULL
     * */
    void onGetOMSAllOrders();

    /* 功能:获取菜品信息
     * 参数:NULL
     * 返回:NULL
     * */
    void onPullDishes();

    /* 功能:获取菜品信息
     * 参数:NULL
     * 返回:NULL
     * */
    void onUpdDishes(QString channelCode, QMap<QString, int> dishes);

    /* 功能:获取菜品信息
     * 参数:NULL
     * 返回:NULL
     * */
    void onUpdDishesForRef(QString channelCode, QMap<QString, int> dishes);

    /* 功能:设置门店营业状态
     * 参数:NULL
     * 返回:NULL
     * */
    void onSetStoreOperatingStatus(const QString& channelCode, const QString& channelName,int business_status);

    /* 功能:向服务端发送 自测请求;
     * 参数:NULL
     * 返回:NULL
     * */
    void onSendSelfCheck();


    /* 功能:向服务端获取日结数据
     * 参数:NULL
     * 返回:NULL
     * */
    void onDailyReport();


    /* 功能:获取Http返回Json数据
     * 参数:NULL
     * 返回:Json对象
     * */
    QJsonObject _PackHttpReplyJson(const int status, const QString& msg, const QJsonObject& data, const int &iscontinue, const QString &orderId);

    /**
    *功能:FM外卖插件为响应Simphony请求准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseHttpRequest(const QJsonObject &content, QJsonObject &data,QString &error);

    /**
    *功能:FM外卖插件为响应Simphony请求[action:01 -> 拉取订单]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseSimphony01Request(const QJsonObject &content, QJsonObject &data,QString &error);

    /**
    *功能:FM外卖插件为响应Simphony请求[action:02 -> 确认订单]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseSimphony02Request(const QJsonObject &content, QJsonObject &data,QString &error);

    /**
    *功能:FM外卖插件为响应Simphony请求[action:03 -> 取消订单]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseSimphony03Request(const QJsonObject &content, QJsonObject &data,QString &error);

    /**
    *功能:FM外卖插件为响应Simphony请求[action:04 -> 汇报订单Sim/POS产生的小票号]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseSimphony04Request(const QJsonObject &content, QJsonObject &data,QString &error);

    /**
    *功能:FM外卖插件为响应Simphony请求[action:05 -> simphony更新订单数据到POS本地数据库以以便POS打印小票及汇总单信息]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseSimphony05Request(const QJsonObject &content, QJsonObject &data,QString &error);


    /**
    *功能:FM外卖插件为响应Simphony请求[action:06 -> simphony汇报SIM录单异常]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseSimphony06Request(const QJsonObject &content, QJsonObject &data,QString &error);


    /**
    *功能:FM外卖插件为响应Simphony请求[action:11 -> Sim/POS推送订单到FM插件]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseOMS11Request(const QJsonObject &content, QJsonObject &data,QString &error);

    /**
    *功能:FM外卖插件为响应OMS推送门店状态 请求[action:12 -> OMS->POS推送门店营业状态]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseOMS12Request(const QJsonObject &content, QJsonObject &data,QString &error);

    /**
    *功能:FM外卖插件为响应OMS推送 宣导提醒消息 请求[action:13 -> OMS->POS 推送宣导提醒消息]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseOMS13Request(const QJsonObject &content, QJsonObject &data, QString &error);

    /**
    *功能:FM外卖插件为响应盒马生鲜 推订单请求[action:21]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseHM21Request(const QJsonObject &content, QJsonObject &data,QString &error);

    /**
    *功能:FM外卖插件响应Simphony请求时，如果外卖插件未登录则进行登陆；
    *参数:1、请求json参数；2、返回错误信息；
    *返回:是否登陆成功；
    **/
    bool _PmsMachineReqTryLogin();

    /**
    *功能:FM外卖插件响应Simphony请求时，如果外卖插件未登录则进行登陆；
    *参数:1、请求json参数；2、返回错误信息；
    *返回:是否登陆成功；
    **/
    bool _ResponseSimReqTryLogin(const QJsonObject &content, QString &error);

    /**
    *功能:FM外卖插件为响应Simphony请求[查询FM插件第一条订单数据作为返回数据]准备返回数据
    *参数:1、请求json参数；2、准备返回请求数据的Buff；3、返回错误信息；
    *返回:是否准备成功；
    **/
    bool _ResponseSimReqFristOrderData(const QJsonObject &content,QJsonObject &data,QString &error, const QString &orderId);

};

#endif // FLOWCONTROL_H
