/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



#include "system.h"

#include <osl/diagnose.h> 
#include <osl/time.h>
#include <sys/timeb.h>

extern sal_Bool TimeValueToFileTime(const TimeValue *cpTimeVal, FILETIME *pFTime);

extern BOOL FileTimeToTimeValue( const FILETIME *cpFTime, TimeValue *pTimeVal );

//--------------------------------------------------
// osl_getSystemTime
//--------------------------------------------------

sal_Bool SAL_CALL osl_getSystemTime(TimeValue* pTimeVal)
{
	SYSTEMTIME SystemTime; 
	FILETIME   CurTime, OffTime;
	__int64	   Value;

	OSL_ASSERT(pTimeVal != 0);

	GetSystemTime(&SystemTime);
	SystemTimeToFileTime(&SystemTime, &CurTime);

	SystemTime.wYear         = 1970;
	SystemTime.wMonth        = 1;
    SystemTime.wDayOfWeek    = 0;
    SystemTime.wDay          = 1;
    SystemTime.wHour         = 0;
    SystemTime.wMinute       = 0;
    SystemTime.wSecond       = 0;
    SystemTime.wMilliseconds = 0;

	SystemTimeToFileTime(&SystemTime, &OffTime);

	Value = *((__int64 *)&CurTime) - *((__int64 *)&OffTime);

	pTimeVal->Seconds  = (unsigned long) (Value / 10000000L);
	pTimeVal->Nanosec  = (unsigned long)((Value % 10000000L) * 100);

	return (sal_True);
}

//--------------------------------------------------
// osl_getDateTimeFromTimeValue
//--------------------------------------------------

sal_Bool SAL_CALL osl_getDateTimeFromTimeValue( TimeValue* pTimeVal, oslDateTime* pDateTime )
{
	FILETIME	aFileTime;
	SYSTEMTIME	aSystemTime;

	if ( TimeValueToFileTime(pTimeVal, &aFileTime) )
	{
		if ( FileTimeToSystemTime( &aFileTime, &aSystemTime ) )
		{
			pDateTime->NanoSeconds	=	pTimeVal->Nanosec;

			pDateTime->Seconds		=	aSystemTime.wSecond;
			pDateTime->Minutes		=	aSystemTime.wMinute;
			pDateTime->Hours		=	aSystemTime.wHour;
			pDateTime->Day			=	aSystemTime.wDay;
			pDateTime->DayOfWeek	=	aSystemTime.wDayOfWeek;
			pDateTime->Month		=	aSystemTime.wMonth;
			pDateTime->Year			=	aSystemTime.wYear;

			return sal_True;
		}
	} 

	return sal_False;
}

//--------------------------------------------------
// osl_getTimeValueFromDateTime
//--------------------------------------------------

sal_Bool SAL_CALL osl_getTimeValueFromDateTime( oslDateTime* pDateTime, TimeValue* pTimeVal )
{
	FILETIME	aFileTime;
	SYSTEMTIME	aSystemTime;

	aSystemTime.wMilliseconds	=	0;
	aSystemTime.wSecond			=	pDateTime->Seconds;
	aSystemTime.wMinute			=	pDateTime->Minutes; 
	aSystemTime.wHour			=	pDateTime->Hours;
	aSystemTime.wDay			=	pDateTime->Day;
	aSystemTime.wDayOfWeek		=	pDateTime->DayOfWeek;
	aSystemTime.wMonth			=	pDateTime->Month;
	aSystemTime.wYear			=	pDateTime->Year;

	if ( SystemTimeToFileTime( &aSystemTime, &aFileTime ) )
	{
		if (FileTimeToTimeValue( &aFileTime, pTimeVal  ) )
		{
			pTimeVal->Nanosec = pDateTime->NanoSeconds;
			return sal_True;
		}
	}

	return sal_False;
}


//--------------------------------------------------
// osl_getLocalTimeFromSystemTime
//--------------------------------------------------

sal_Bool SAL_CALL osl_getLocalTimeFromSystemTime( TimeValue* pSystemTimeVal, TimeValue* pLocalTimeVal )
{ 
	TIME_ZONE_INFORMATION aTimeZoneInformation;
	DWORD Success;
	sal_Int64	bias;

	// get timezone information
	if ( ( Success=GetTimeZoneInformation( &aTimeZoneInformation ) ) != TIME_ZONE_ID_INVALID)
	{
		bias=aTimeZoneInformation.Bias;

		// add bias for daylight saving time
		if ( Success== TIME_ZONE_ID_DAYLIGHT )
			bias+=aTimeZoneInformation.DaylightBias;

		if ( (sal_Int64) pSystemTimeVal->Seconds > ( bias * 60 ) )
		{
			pLocalTimeVal->Seconds = (sal_uInt32) (pSystemTimeVal->Seconds - ( bias * 60) );
			pLocalTimeVal->Nanosec = pSystemTimeVal->Nanosec;

			return sal_True;
		}
	}

	return sal_False; 
}

//--------------------------------------------------
// osl_getSystemTimeFromLocalTime
//--------------------------------------------------

sal_Bool SAL_CALL osl_getSystemTimeFromLocalTime( TimeValue* pLocalTimeVal, TimeValue* pSystemTimeVal )
{
	TIME_ZONE_INFORMATION aTimeZoneInformation;
	DWORD Success;
	sal_Int64	bias;

	// get timezone information
	if ( ( Success=GetTimeZoneInformation( &aTimeZoneInformation ) ) != TIME_ZONE_ID_INVALID)
	{
		bias=aTimeZoneInformation.Bias;

		// add bias for daylight saving time
		if ( Success== TIME_ZONE_ID_DAYLIGHT )
			bias+=aTimeZoneInformation.DaylightBias; 

		if ( (sal_Int64) pLocalTimeVal->Seconds + ( bias * 60 ) > 0 )
		{
			pSystemTimeVal->Seconds = (sal_uInt32) ( pLocalTimeVal->Seconds + ( bias * 60) );
			pSystemTimeVal->Nanosec = pLocalTimeVal->Nanosec;

			return sal_True;
		}
	}

	return sal_False; 
}


static struct _timeb startTime;
static sal_Bool bGlobalTimer = sal_False;

sal_uInt32 SAL_CALL osl_getGlobalTimer(void)
{
  struct _timeb currentTime;
  sal_uInt32 nSeconds;

  if ( bGlobalTimer == sal_False )
  {
      _ftime( &startTime );
      bGlobalTimer=sal_True;
  }
  
  _ftime( &currentTime );
  
  nSeconds = (sal_uInt32)( currentTime.time - startTime.time );

  return ( nSeconds * 1000 ) + (long)( currentTime.millitm - startTime.millitm );
}

