#pragma once
#include <winsock2.h>
#include "pcap.h"
#include "windows.h"
#include "easylog/easylogging++.h"
#include <iphlpapi.h>

#include <remote-ext.h>
#include <iostream>
#include <map>
#include <thread>
#include <mutex>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib,"wpcap.lib")

#include "wintoastlib.h"

/* 4 bytes IP address */
typedef struct ip_address
{
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
}ip_address;

/* IPv4 header */
typedef struct ip_header
{
    u_char	ver_ihl;		// Version (4 bits) + Internet header length (4 bits)
    u_char	tos;			// Type of service 
    u_short tlen;			// Total length 
    u_short identification; // Identification
    u_short flags_fo;		// Flags (3 bits) + Fragment offset (13 bits)
    u_char	ttl;			// Time to live
    u_char	proto;			// Protocol
    u_short crc;			// Header checksum
    ip_address	saddr;		// Source address
    ip_address	daddr;		// Destination address
    u_int	op_pad;			// Option + Padding
}ip_header;

/* TCP header*/
typedef struct tcp_header
{
    u_short sport;            //源端口号  16
    u_short dport;             //目的端口号  16+16=32
    u_int th_seq;                //序列号  32->4
    u_int th_ack;               //确认号  4
    u_char th1; //: 4;              //tcp头部长度  1
    //u_int th_res : 4;             //6位中的4位首部长度  
    //u_char th_res2; //: 2;            //6位中的2位首部长度  
    u_char th_flags;            //6位标志位  
    u_short th_win;             //16位窗口大小  
    u_short th_sum;             //16位tcp检验和  
    u_short th_urp;             //16位紧急指针  
}tcp_header;


typedef struct {
    u_char dest_addr[6];
    u_char src_addr[6];
    u_char type[2];
}mac_header;


class Packet {
public:
    Packet();
	~Packet();

    void Init();
    int Run();
    bool LogoutPLM();  //退出plm系统

    void UpdateStartTime() {
        std::lock_guard<std::mutex> lock(m_timeLock);
        m_startTime = time(nullptr);
    }

    time_t GetStartTime() {
        std::lock_guard<std::mutex> lock(m_timeLock);
        return m_startTime;
    }

    void SetShowToast(bool flag) {
        m_isShowToast = flag;
    }

private:
	bool CheckKeepAlive(u_char* option);  //无用
    void CheckTimeOut(u_short sport, u_short dport, const std::string& tcpInfoStr);   //检测是否超时
    unsigned long ConvertMaskToULong(const std::string& maskString);
    INT64 PopToast();
    BOOL WaitUserHandle(LPWSTR command_line, DWORD* exit_code);   //创建ui进程
    void UserHandleProc();
    static void FtpPacketHandler(const struct pcap_pkthdr* header, const u_char* pkt_data);
    static void PacketHandler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data);

private:
    int m_hbPort;//心跳端口
    time_t m_startTime;    //开始时间
    int m_intervalTime;  //时间间隔 s

    pcap_t* m_adhandle;
    std::string m_serverIp;   //服务器ip

    //bool m_quitPlmFlag;   //退出plm标记
    std::mutex m_timeLock;    //锁

    bool m_quitFlag;   //退出标记
    std::thread m_checkThread;    //检测线程
    bool m_isShowToast;   //是否弹出了toast;
    

};

class MyToastHandler :public WinToastLib::IWinToastHandler {
public:

    MyToastHandler(Packet* packet):m_packet(packet) {}

    void toastActivated()const {
        LOG(DEBUG) << "The user clicked in this toast" ;
        m_packet->SetShowToast(false);
    }

    void toastActivated(int actionIndex)const {
        LOG(DEBUG) << "The user clicked on action #" << actionIndex;
        m_packet->SetShowToast(false);
        //if (actionIndex == 0) { //确定  马上退出
        //    if(m_packet) m_packet->LogoutPLM();
        //}
        //else if (actionIndex == 1) {  //取消 不退出
        //    if (m_packet) m_packet->ResetQuitFlag();
        //}
    }


    void toastDismissed(WinToastDismissalReason state) const {
        switch (state) {
        case UserCanceled:
            LOG(DEBUG) << "The user dismissed this toast";
            //exit(1);
            break;
        case TimedOut:
            LOG(DEBUG) << "The toast has timed out";
            //exit(2);
            break;
        case ApplicationHidden:
            LOG(DEBUG) << "The application hid the toast using ToastNotifier.hide()";
            //exit(3);
            break;
        default:
            LOG(DEBUG) << "Toast not activated";
            //exit(4);
            break;
        }
        m_packet->SetShowToast(false);
    }
    void toastFailed() const {
        LOG(ERROR) << "Error showing current toast";
    }

private:
    Packet*  m_packet;
};

