/*
 * synergy -- mouse and keyboard sharing utility
 * Copyright (C) 2012-2016 Symless Ltd.
 * Copyright (C) 2002 Chris Schoeneman
 * 
 * This package is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * found in the file LICENSE that should have accompanied this file.
 * 
 * This package is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "arch/win32/ArchTimeWindows.h"

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

#define MMNODRV         // Disable: Installable driver support
#define MMNOSOUND       // Disable: Sound support
#define MMNOWAVE        // Disable: Waveform support
#define MMNOMIDI        // Disable: MIDI support
#define MMNOAUX         // Disable: Auxiliary audio support
#define MMNOMIXER       // Disable: Mixer support
#define MMNOJOY         // Disable: Joystick support
#define MMNOMCI         // Disable: MCI support
#define MMNOMMIO        // Disable: Multimedia file I/O support
#define MMNOMMSYSTEM    // Disable: General MMSYSTEM functions
#include <MMSystem.h>

typedef WINMMAPI DWORD (WINAPI *PTimeGetTime)(void);

static double            s_freq       = 0.0;
static HINSTANCE        s_mmInstance = NULL;
static PTimeGetTime        s_tgt        = NULL;


//
// ArchTimeWindows
//

ArchTimeWindows::ArchTimeWindows()
{
    assert(s_freq == 0.0 || s_mmInstance == NULL);

    LARGE_INTEGER freq;
    if (QueryPerformanceFrequency(&freq) && freq.QuadPart != 0) {
        s_freq = 1.0 / static_cast<double>(freq.QuadPart);
    }
    else {
        // load winmm.dll and get timeGetTime
        s_mmInstance = LoadLibrary("winmm");
        if (s_mmInstance != NULL) {
            s_tgt = (PTimeGetTime)GetProcAddress(s_mmInstance, "timeGetTime");
        }
    }
}

ArchTimeWindows::~ArchTimeWindows()
{
    s_freq = 0.0;
    if (s_mmInstance == NULL) {
        FreeLibrary(static_cast<HMODULE>(s_mmInstance));
        s_tgt        = NULL;
        s_mmInstance = NULL;
    }
}

double
ArchTimeWindows::time()
{
    // get time.  we try three ways, in order of descending precision
    if (s_freq != 0.0) {
        LARGE_INTEGER c;
        QueryPerformanceCounter(&c);
        return s_freq * static_cast<double>(c.QuadPart);
    }
    else if (s_tgt != NULL) {
        return 0.001 * static_cast<double>(s_tgt());
    }
    else {
        return 0.001 * static_cast<double>(GetTickCount());
    }
}
