// inetcmon(InterNET-Connected-MONitor) by (-_-)

#pragma comment(lib, "Kernel32.lib")

#include <cstdio>
#include <cstdlib>
#include <deque>
#include <windows.h>

using namespace std;

typedef HRESULT (*IS_INTERNET_CONNECTED_PROC)(void);

typedef struct {
    bool connected;
    DWORD tickCount;
} RECORD;

static const DWORD DEFAULT_INTERVAL_SECS = 1;
static const DWORD M1_MILLISECS = 60 * 1000;
static const DWORD M10_MILLISECS = 10 * M1_MILLISECS;
static const DWORD M30_MILLISECS = 30 * M1_MILLISECS;
static const DWORD H1_MILLISECS = 60 * M1_MILLISECS;
static const DWORD H2_MILLISECS = 2 * H1_MILLISECS;

int main(int argc, char** argv) {
    if (argc > 2) {
        fprintf(stderr, "usage: %s [intervalSecs=%d]\n", argv[0], DEFAULT_INTERVAL_SECS);
        return 1;
    }
    DWORD intervalSecs = DEFAULT_INTERVAL_SECS;
    if (argc >= 2) {
        DWORD intervalSecs = atoi(argv[1]);
    }
    DWORD intervalMillisecs = intervalSecs * 1000;
	
    HMODULE connectDllModuleHandle = LoadLibrary("Connect.dll");
    if (connectDllModuleHandle == NULL) {
        fprintf(stderr, "error: GetModuleHandle\n");
        return 1;
    }
    IS_INTERNET_CONNECTED_PROC IsInternetConnectedProc = 
        (IS_INTERNET_CONNECTED_PROC)GetProcAddress(connectDllModuleHandle, "IsInternetConnected");
    if (IsInternetConnectedProc == NULL) {
        fprintf(stderr, "error: GetProcAddress\n");
        return 1;
    }
	
    deque<RECORD> recordDeque;
    for (;;) {
        DWORD now = GetTickCount();
        RECORD record;
        record.tickCount = now;
        record.connected = IsInternetConnectedProc() == S_OK;
        recordDeque.push_front(record);
        
        unsigned int m1DisconnectedSectionCount = 0;
        unsigned int m10DisconnectedSectionCount = 0;
        unsigned int m30DisconnectedSectionCount = 0;
        unsigned int h1DisconnectedSectionCount = 0;
        unsigned int h2DisconnectedSectionCount = 0;
        bool previousConnected = true;
        DWORD lastConnectedSectionStart = now;
        bool lastConnectedSectionInside = true;
        for (deque<RECORD>::iterator iter = recordDeque.begin(); iter != recordDeque.end(); iter++) {
            DWORD elapsedMillisecs = now - iter->tickCount;
            if (elapsedMillisecs >= H2_MILLISECS) {
                recordDeque.erase(iter, recordDeque.end());
                break;
            }
            bool disconnectedSectionEntering = previousConnected && !iter->connected;
            if (disconnectedSectionEntering) h2DisconnectedSectionCount++;
            if (elapsedMillisecs < H1_MILLISECS) {
                if (disconnectedSectionEntering) h1DisconnectedSectionCount++;
                if (elapsedMillisecs < M30_MILLISECS) {
                    if (disconnectedSectionEntering) m30DisconnectedSectionCount++;
                    if (elapsedMillisecs < M10_MILLISECS) {
                        if (disconnectedSectionEntering) m10DisconnectedSectionCount++;
                        if (elapsedMillisecs < M1_MILLISECS) {
                            if (disconnectedSectionEntering) m1DisconnectedSectionCount++;
                        }
                    }
                }
            }
            if (lastConnectedSectionInside) {
                if (!iter->connected) {
                    lastConnectedSectionInside = false;
                }
                else {
                    lastConnectedSectionStart = iter->tickCount;
                }
            }
            previousConnected = iter->connected;
        }
        DWORD lastConnectedSectionMillisecs = now - lastConnectedSectionStart;
        DWORD lastConnectedSectionSeconds = lastConnectedSectionMillisecs / 1000;
        DWORD lastConnectedSectionMinutes = lastConnectedSectionSeconds / 60;
        DWORD lastConnectedSectionHours = lastConnectedSectionMinutes / 60;
        printf("%-12s 1m:%3d 10m:%3d 30m:%3d 1h:%3d 2h:%3d lastc:%02d:%02d:%02d\n", 
            record.connected ? "CONNECTED" : "DISCONNECTED", 
            m1DisconnectedSectionCount, 
            m10DisconnectedSectionCount, 
            m30DisconnectedSectionCount, 
            h1DisconnectedSectionCount, 
            h2DisconnectedSectionCount, 
            lastConnectedSectionHours % 24, 
            lastConnectedSectionMinutes % 60, 
            lastConnectedSectionSeconds % 60);
        
        Sleep(intervalMillisecs);
    }
    return 0;
}
