/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
*
* This software is dual-licensed to you under the MIT License (MIT) and
* the Universal Permissive License (UPL). See the LICENSE file in the root
* directory for license terms. You may choose either license, or both.
*/

#include <stdio.h>
#include <time.h>
#include <math.h>
#include <time.h>
#include <openssl/err.h>
#include <winsock2.h>
#include "iotcs_port_system.h"
#include "iotcs_port_time.h"

/* It is difference between real time and current time
 * IoT Server return real time and to avoid getting of
 * sudo permission we use that difference.
 */
static int64_t g_diff_seconds = 0;

int gettimeofday(struct timeval *result, struct timezone *tz)
{
	/** shift is difference between 1970-Jan-01 & 1601-Jan-01
	 * in 100-nanosecond intervals
	 */
	const uint64_t shift = 116444736000000000ULL; // (27111902 << 32) + 3577643008

	SYSTEMTIME local_time;
	FILETIME file_time;

	GetSystemTime( &local_time);
	SystemTimeToFileTime(&local_time, &file_time);

	result->tv_sec = (long)(((uint64_t)file_time.dwLowDateTime +
		(((uint64_t)file_time.dwHighDateTime) << 32) - shift) / 10000000L);

	result->tv_usec = (long)(local_time.wMilliseconds * 1000);

	return 0;
}

int iotcs_port_sleep_millis(int32_t timeout_ms) {

    Sleep(timeout_ms);
    return 0;
}

int64_t iotcs_port_get_current_time_millis(void) {
	struct timeval t;
	gettimeofday(&t, NULL);
    return IOTCS_TIMEVAL_TO_MILLISEC(&t) + IOTCS_SEC_TO_MILLISEC(g_diff_seconds);
}

void iotcs_port_set_current_time(int64_t seconds) {
    g_diff_seconds = seconds - IOTCS_MILLISEC_TO_SEC(iotcs_port_get_current_time_millis());
}

void timeradd(struct timeval *a, struct timeval *b, struct timeval *res)
{
    res->tv_sec = a->tv_sec + b->tv_sec;
    res->tv_usec = a->tv_usec + b->tv_usec;

    if (res->tv_usec >= 1000000) {
        ++res->tv_sec;
        res->tv_usec -= 1000000;
    }
}

void timersub(struct timeval *a, struct timeval *b, struct timeval *res)
{
    res->tv_sec = a->tv_sec - b->tv_sec;
    res->tv_usec = a->tv_usec - b->tv_usec;

    if (res->tv_usec < 0) {
        --res->tv_sec;
        res->tv_usec += 1000000;
    }
}

const char *iotcs_port_get_os_name(void) {
    return getenv("IOTCS_OS_NAME");
}

const char *iotcs_port_get_os_version(void) {
    return getenv("IOTCS_OS_VERSION");
}

const char *iotcs_port_get_http_proxy(void) {
    return getenv("IOTCS_HTTP_PROXY");
}

void iotcs_port_platform_init() {
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
}

void iotcs_port_thread_cleanup() {
	ERR_remove_thread_state(0);
}

void iotcs_port_platform_finilize() {
}
