/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


#include <ddbasetime.h>
#include <sys/time.h>
#include <cstdio>
#include <stdexcept>
#include <time.h>

using namespace std;


/**
	Default constructor. 
	Creates a representation of the current time.
*/

ddbasetime::ddbasetime()
{
   struct timeval tv;
   ::gettimeofday( &tv, 0 );
   time_t ltime = tv.tv_sec;
   tm* t = ::localtime( &ltime );
	_millis = (size_t)( MSECS_PER_HOUR*t->tm_hour + MSECS_PER_MIN*t->tm_min + 1000*t->tm_sec + tv.tv_usec/1000 );
}


/**
  Constructs a time with hour  h, minute  m, seconds  s and
  milliseconds ms.
  h must be in the range 0-23, m and s must be in the range
  0-59, and ms must be in the range 0-999.
*/

ddbasetime::ddbasetime( int h, int m, int s, int ms )
{
    set_hms( h, m, s, ms );
}


/**
  Constructs a time from time_t "local"
*/

ddbasetime::ddbasetime( time_t local )
{
	tm* t = ::localtime( &local );
	_millis = (size_t)( MSECS_PER_HOUR*t->tm_hour + MSECS_PER_MIN*t->tm_min + 1000*t->tm_sec );
}


/**
	Copy constructor.
*/


ddbasetime::ddbasetime( const ddbasetime& src )
: ddbasetimeval()
{
	*this = src;
}


/**
	Assignment operator.
*/


ddbasetime& ddbasetime::operator=( const ddbasetime& src )
{
	if( this != &src )
		_millis = src._millis;
	return *this;
}


/**
	Destructor
*/

ddbasetime::~ddbasetime()
{

}

bool ddbasetime::operator==( const ddbasetime& src ) const
{
	return _millis == src._millis;
}

bool ddbasetime::operator!=( const ddbasetime& src ) const
{
	return _millis != src._millis;
}

bool ddbasetime::operator<( const ddbasetime& src ) const
{
	return _millis < src._millis;
}

bool ddbasetime::operator<=( const ddbasetime& src ) const
{
	return _millis <= src._millis;
}

bool ddbasetime::operator>( const ddbasetime& src ) const
{
	return _millis > src._millis;
}

bool ddbasetime::operator>=( const ddbasetime& src ) const
{
	return _millis >= src._millis;
}


/**

*/

int ddbasetime::get( size_t field ) const
{

	switch( field )
	{
			
		case tf_millis :
		
			return _millis % 1000;
			
		case tf_seconds : 	
		
			return ( _millis / 1000 ) % SECS_PER_MIN;		
			
		case tf_minutes :  
		
			return ( _millis % MSECS_PER_HOUR ) / MSECS_PER_MIN;
			
		case tf_hours : 
			
			return _millis / MSECS_PER_HOUR; 
			
		case tf_days : 
		case tf_weeks : 	
			
			return 0;			
			
		default:
		
			throw runtime_error("ddbasetime::get: invalid field value!" );
		
	}
	return 0;
}

/**
	
*/

/**
  Sets the time to hour  h, minute  m, seconds  s and
  milliseconds  ms.
  h must be in the range 0-23,  m and  s must be in the range
  0-59, and  ms must be in the range 0-999. Returns true if the set
  time is valid, otherwise false.

*/

bool ddbasetime::set_hms( int h, int m, int s, int ms )
{
	if ( !is_valid( h,m,s,ms ) )
	{
		_millis = MSECS_PER_DAY;		// make this invalid
		return false;
  }
  _millis = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms;
  return true;
}


/**
  Returns true if the time is valid, or false if the time is invalid.
  The time 23:30:55.746 is valid, while 24:12:30 is invalid.
*/

bool ddbasetime::is_valid() const
{
    return _millis < MSECS_PER_DAY;
}


/**
  Returns a ddbasetime object containing a time  nsecs seconds later than
  the time of this object (or earlier if  ms is negative).
*/

ddbasetime& ddbasetime::add_secs( int nsecs )
{
    return add_milli_secs(nsecs*1000);
}


/**
  Returns the number of seconds from this time to  t (which is
  negative if  t is earlier than this time).

  Since ddbasetime measures time within a day and there are 86400 seconds
  in a day, the result is between -86400 and 86400.
*/

int ddbasetime::get_secs_to( const ddbasetime& src ) const
{
    return ( (int)src._millis - (int) _millis )/1000;
}

/**
  Returns a ddbasetime object containing a time  ms milliseconds later than
  the time of this object (or earlier if  ms is negative).

  Note that the time will wrap if it passes midnight. See addSecs()
  for an example.

*/

ddbasetime& ddbasetime::add_milli_secs( int ms ) 
{
	//ddbasetime t;
   if ( ms < 0 )
	{	
		int negdays = (MSECS_PER_DAY-ms) / MSECS_PER_DAY;
		_millis = ( (int) _millis + ms + negdays*MSECS_PER_DAY) % MSECS_PER_DAY;
   }
	else
	{
		_millis = ( (int) _millis + ms ) % MSECS_PER_DAY;
   }
   return *this;
}


/**
  Returns the number of milliseconds from this time to  t (which is
  negative if  t is earlier than this time).

  Since ddbasetime measures time within a day and there are 86400000
  milliseconds in a day, the result is between -86400000 and 86400000.

*/

int ddbasetime::get_milli_secs_to( const ddbasetime& src ) const
{
	return (int) src._millis - (int) _millis;
}


/**
	FIX!
	Creates a localized ddstring representation of this object. 
	Calls ddsystem.format()
*/
/**
  Returns the time of this object in a textual format. Milliseconds
  are not included. The ddstring format is HH:MM:SS, e.g. 1 second
  before midnight would be "23:59:59".
*/

ddstring ddbasetime::to_string() const
{
	char buf[10];
  ::snprintf( buf, sizeof(buf), "%.2d:%.2d:%.2d", get_hours(), get_minutes(), get_seconds() );
  return ddstring(buf);	 
}


/**
  Returns the time of this object in a textual format. Milliseconds
  are included. The ddstring format is HH:MM:SS:mmm, e.g. 1 millisecond
  before midnight would be "23:59:59:999".
*/

ddstring ddbasetime::to_string_ms() const
{   
	char buf[13];
  ::snprintf( buf, sizeof(buf), "%.2d:%.2d:%.2d:%.3d", get_hours(), get_minutes(), get_seconds(), get_millis() );
  return ddstring(buf); 
}


/**
  Returns the current time, as reported by the system clock.
*/


ddbasetime ddbasetime::now()
{
  ddbasetime ct;
  return ct;
}


/**
  Returns true if the specified time is valid, otherwise false.
  The time is valid if  h is in the range 0-23,  m and  s are in
  the range 0-59, and  ms is in the range 0-999.
*/

bool ddbasetime::is_valid( int h, int m, int s, int ms )
{
    return (size_t) h < 24 && (size_t) m < 60 && (size_t) s < 60 && (size_t) ms < 1000;
}


/**
  Sets this time to the current time. This is practical for timing.
*/

void ddbasetime::start()
{
	*this = ddbasetime::now();
}


/**
  Sets this time to the current time, and returns the number of
  seconds that have elapsed since the last time "start()" or
  "restart()" was called
*/

double ddbasetime::restart()
{
  ddbasetime t;
  int n = get_milli_secs_to( t );
  if ( n < 0 )				// passed midnight
  	n += 86400*1000;
  *this = t;
  return (double) n / 1000.0;
}


/**
  Returns the number of seconds that have elapsed since the last
  ddbasetime "start()" or "restart()" was called.
*/

double ddbasetime::elapsed()
{
	int n = get_milli_secs_to( now() );
	if ( n < 0 )				// passed midnight
		n += 86400*1000;
	return (double) n / 1000.0 ;
}


/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


/**
	Default constructor.
	Creates a representation of the current date.	
*/

ddbasedate::ddbasedate()
{
  ::time( &_epoch );  		
}

	
ddbasedate::ddbasedate( time_t epoch )
: _epoch( epoch )
{

}

/**
	Copy constructor.
*/


ddbasedate::ddbasedate( const ddbasedate& src )
: ddbasetimeval()
{
	*this=src;
}



/**
	Assignment operator.
*/

ddbasedate& ddbasedate::operator=( const ddbasedate& src )
{
	if( this != &src )
		_epoch = src._epoch;
	return *this;
}


/**
	Destructor
*/

ddbasedate::~ddbasedate()
{

}

bool ddbasedate::operator==( const ddbasedate& src ) const
{
	return _epoch == src._epoch;
}

bool ddbasedate::operator!=( const ddbasedate& src ) const
{
	return _epoch != src._epoch;
}

bool ddbasedate::operator<( const ddbasedate& src ) const
{
	return _epoch < src._epoch;
}

bool ddbasedate::operator<=( const ddbasedate& src ) const
{
	return _epoch <= src._epoch;
}

bool ddbasedate::operator>( const ddbasedate& src ) const
{
	return _epoch > src._epoch;
}

bool ddbasedate::operator>=( const ddbasedate& src ) const
{
	return _epoch >= src._epoch;
}
	

int ddbasedate::get( size_t field ) const
{
	switch( field )
	{
			
		case tf_millis : 
		case tf_seconds : 			
		case tf_minutes : 
		case tf_hours : 
		case tf_days : 
		case tf_weeks : 
		case tf_months : 
		case tf_years : 
		case tf_dom :
		case tf_dow : 
		case tf_doy :
			
			return 0;			
			
		default:
		
			throw runtime_error("ddbasedate::get: invalid field value!" );
		
	}
	return 0;
}



/**
	Creates a ddstring representation of this object. 
*/

ddstring ddbasedate::to_string() const
{
	char buf[30];
  struct tm tmptime;
 	::asctime_r( ::localtime_r( &_epoch, &tmptime ), buf );
	buf[24] = 0;
	ddstring result;   
	result.append( buf );	
	return result;
}

ddstring ddbasedate::to_string( const ddstring& format ) const
{
	struct tm tmptime;
	char buf[50];
	ddstring result;   
	::localtime_r( &_epoch, &tmptime );
  if( ::strftime( buf, 49, format.c_str(), &tmptime ) )
		result.assign( buf );
	return result;
}


ddstring ddbasedate::to_string_gmt() const
{
	char buf[30];
  struct tm tmptime;
 	::asctime_r( ::gmtime_r( &_epoch, &tmptime ), buf );
	buf[24] = 0;
	ddstring result;   
	result.append( buf );	
	return result;
}

ddstring ddbasedate::to_string_de() const
{
	struct tm tm_now;
	char buf[50];
	::localtime_r( &_epoch, &tm_now );
	::strftime( buf, 49, "%d.%m.%Y", &tm_now );
	ddstring result;   
	result.append( buf );	
	return result;
}	


ddstring ddbasedate::to_string_en() const
{
	char buf[30];
	struct tm tm_now;
	::localtime_r( &_epoch, &tm_now );
	::strftime( buf, 29, "%F", &tm_now );
	ddstring result;   
	result.append( buf );	
	return result;
}
	
	
ddstring ddbasedate::to_string_mysql() const
{
	char buf[30];
	struct tm tm_now;
	::localtime_r( &_epoch, &tm_now );
	::strftime( buf, 29, "%F %T", &tm_now );
	ddstring result;   
	result.append( buf );	
	return result;
}


ddbasedate ddbasedate::now()
{
	ddbasedate nowdate;
	return nowdate;
}
