//
//  osxtads_time.m
//  XTads
//
//  Created by Rune Berg on 12/07/2020.
//  Copyright © 2020 Rune Berg. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "osxtads_support.h"


/*
 *   Sleep for a given interval.  This should simply pause for the given
 *   number of milliseconds, then return.  On multi-tasking systems, this
 *   should use a system API to suspend the current process for the desired
 *   delay; on single-tasking systems, this can simply sit in a wait loop
 *   until the desired interval has elapsed.
 */
void os_sleep_ms( long ms )
{
	// Note: the timeDelay() T3 function calls this
	
	XTOSIFC_DEF_SELNAME(@"os_sleep_ms");
	XTOSIFC_TRACE_1(@"ms=%ld", ms);
	
	double seconds = ((double)ms) / 1000.0f;
	
	[getGameRunner() sleepFor:seconds];
}

/*
 *   Get the current system high-precision timer.  This function returns a
 *   value giving the wall-clock ("real") time in milliseconds, relative to
 *   any arbitrary zero point.  It doesn't matter what this value is relative
 *   to -- the only important thing is that the values returned by two
 *   different calls should differ by the number of actual milliseconds that
 *   have elapsed between the two calls.  This might be the number of
 *   milliseconds since the computer was booted, since the current user
 *   logged in, since midnight of the previous night, since the program
 *   started running, since 1-1-1970, etc - it doesn't matter what the epoch
 *   is, so the implementation can use whatever's convenient on the local
 *   system.
 */
long
os_get_sys_clock_ms( void )
{
	XTOSIFC_DEF_SELNAME(@"os_get_sys_clock_ms");
	
	static NSDate *zeroPoint = nil;
	NSDate *now = [NSDate date];
	if (zeroPoint == nil) {
		zeroPoint = now;
	}
	NSTimeInterval secondsElapsed = [now timeIntervalSinceDate:zeroPoint];
	if (secondsElapsed < 0.0) {
		XTOSIFC_WARN_0(@"secondsElapsed < 0.0");
		secondsElapsed = 0.0;
	}
	double millisecondsElapsed = secondsElapsed * 1000.0;
	long ret = millisecondsElapsed;
	
	XTOSIFC_TRACE_1(@"-> %ld", ret);
	
	return ret;
}

/*
 *   Higher-precision time.  This retrieves the same time information as
 *   os_time() (i.e., the elapsed time since the standard Unix Epoch, January
 *   1, 1970 at midnight UTC), but retrieves it with the highest precision
 *   available on the local system, up to nanosecond precision.  If less
 *   precision is available, that's fine; just return the time to the best
 *   precision available, but expressed in terms of the number of
 *   nanoseconds.  For example, if you can retrieve milliseconds, you can
 *   convert that to nanoseconds by multiplying by 1,000,000.
 *
 *   On return, fills in '*seconds' with the number of whole seconds since
 *   the Epoch, and fills in '*nanoseconds' with the fractional portion,
 *   expressed in nanosceconds.  Note that '*nanoseconds' is merely the
 *   fractional portion of the time, so 0 <= *nanoseconds < 1000000000.
 */
void
os_time_ns( os_time_t* seconds, long* nanoseconds )
{
	// vmdate.cpp (caldate_t::now) calls this
	
	XTOSIFC_DEF_SELNAME(@"os_time_ns");

	NSDate *now = [NSDate date];
	NSTimeInterval secondsSince1970 = now.timeIntervalSince1970;
	
	NSTimeInterval roundedDownSecondsSince1970 = floor(secondsSince1970);
	
	NSTimeInterval partialSecond = secondsSince1970 - roundedDownSecondsSince1970;
	if (partialSecond < 0.0 || partialSecond >= 1.0) {
		XTOSIFC_ERROR_1(@"partialSecond == %lf", partialSecond);
	}
	double partialSecondAsNanoSecs = 1000000000.0 * partialSecond;
	if (partialSecondAsNanoSecs < 0.0 || partialSecondAsNanoSecs > 1000000000.0) {
		XTOSIFC_ERROR_1(@"partialSecondAsNanoSecs == %lf", partialSecondAsNanoSecs);
	}
	
	*seconds = (os_time_t)roundedDownSecondsSince1970;
	*nanoseconds = (long)partialSecondAsNanoSecs;
}

