// ---
//
// $Id: time.cpp,v 1.4 2008/07/15 20:33:31 hartwork Exp $
//
// CppTest - A C++ Unit Testing Framework
// Copyright (c) 2003 Niklas Lundell
//
// ---
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// ---

#if (defined(__WIN32__) || defined(WIN32))
# include "winconfig.h"
#else
# include "config.h"
#endif

#include "missing.h"
#include "cpptest-time.h"

#ifdef HAVE_GETTIMEOFDAY
	#ifdef HAVE_SYS_TIME_H
		#include <sys/time.h>
	#else
		#include <time.h>
	#endif
#endif

using namespace std;

namespace Test
{
	namespace
	{
		const unsigned int UsecPerSec = 1000000;

	} // anonymous namespace

	/// Constructs a time object with zeroed time.
	///
	Time::Time()
	:	_sec(0),
		_usec(0)
	{}

	/// Constructs a time object.
	///
	/// \param sec  Seconds.
	/// \param usec Micro-seconds.
	///
	Time::Time(unsigned int sec, unsigned int usec)
	:	_sec(sec),
		_usec(usec)
	{}

	/// \return Seconds.
	///
	unsigned int
	Time::seconds() const
	{
		return _sec;
	}

	/// \return Micro-seconds.
	///
	unsigned int
	Time::microseconds() const
	{
		return _usec;
	}

	/// \return The current time.
	///
	Time
	Time::current()
	{
		struct timeval tv;
		gettimeofday(&tv, 0);
		return Time(tv.tv_sec, tv.tv_usec);
	}

	/// \relates Time
	///
	/// Computes the time elapsed between two time values.
	///
	/// \param t1 Left-hand time, should be greater than \a t2.
	/// \param t2 Right-hand time, should be less than \a t1.
	///
	/// \return Computed time value.
	///
	Time
	operator-(const Time& t1, const Time& t2)
	{
		if (t2._sec > t1._sec || (t2._sec == t1._sec && t2._usec > t1._usec))
			return Time();

		unsigned int sec = t1._sec - t2._sec;
		unsigned int usec;

		if (t2._usec > t1._usec)
		{
			--sec;
			usec = UsecPerSec - (t2._usec - t1._usec);
		}
		else
			usec = t1._usec - t2._usec;

		return Time(sec, usec);
	}

	/// \relates Time
	///
	/// Adds two time values.
	///
	/// \param t1 Left-hand time.
	/// \param t2 Right-hand time.
	///
	/// \return Computed time value.
	///
	Time
	operator+(const Time& t1, const Time& t2)
	{
		unsigned int sec  = t1._sec + t2._sec;
		unsigned int usec = t1._usec + t2._usec;

		if (usec > UsecPerSec)
		{
			++sec;
			usec -= UsecPerSec;
		}
		return Time(sec, usec);
	}

	/// \relates Time
	///
	/// Outputs a time to an output stream.
	///
	/// \param os Output stream to write to.
	/// \param t  %Time to output.
	///
	/// \return A reference to the given output stream.
	///
	ostream&
	operator<<(ostream& os, const Time& t)
	{
		int old_fill(os.fill());
		int old_width(os.width());

		os << t.seconds() << '.';
		os.fill('0');
		os.width(6);
		os << t.microseconds();

		os.fill(old_fill);
		os.width(old_width);

		return os;
	}

} // namespace Test

