/**
 * @file
 */
#ifndef UI_UTIL_TIME_HPP
#define UI_UTIL_TIME_HPP

// STDC++
#include <string>

// C++ libraries
#include <ui-utilcpp/Exception.hpp>

namespace UI {
namespace Util {

/** @brief Get "sec"-part from gettimeofday(2). */
long int getTimeValSec();

/** @brief Get "usec"-part from gettimeofday(2). */
long int getTimeValUSec();

/** @brief No Signal Sleep: Using POSIX nanosleep(2).
 *
 * @see nanosleep(2), POSIX.1.
 *
 * @return Return values of POSIX nanosleep(2) call (0 for no error).
 *
 */
unsigned int nanosleep(unsigned int seconds, long int nanoseconds);

/** @brief No Signal Seconds Sleep: Using POSIX nanosleep(2).
 *
 * You may use this as drop-in replacement for sleep(3) if you do
 * not want any signals to be raised.
 *
 * @see nanosleep.
 */
unsigned int nssleep(unsigned int seconds);

/** @brief No Signal Nano Sleep.
 *
 * @see nanosleep.
 */
unsigned int nsnsleep(long int nanoseconds);


/** @brief RealTimeStamp class encapsulating "gettimeofday".
 *
 * @see time(2) (POSIX), gettimeofday(2) (BSD).
 */
class RealTimeStamp
{
public:
	/** @brief Error codes for exceptions. */
	enum ErrorCode
	{
		NegativeStamp_=1
	};
	/** @brief This classes exceptions. */
	typedef CodeException<ErrorCode> Exception;

	/** @brief Standard constructor.
	 *
	 * @param sec Seconds since Epoch.
	 * @param usec Micro (10^-6) seconds since Epoch+sec.
	 * @note Values will be "normalised" (make microseconds < 10^6). Altogether, it must not
	 * be a negative date (before Epoch).
	 */
	RealTimeStamp(long int const & sec=0, long int const & usec=0);

	/** @brief Set time stamp manually.
	 *
	 * @param sec Seconds since Epoch.
	 * @param usec Micro (10^-6) seconds since Epoch+sec.
	 * @returns Reference to itself
	 */
	RealTimeStamp & set(long int const & sec, long int const & usec);

	/** @brief Set this stamp to maximum. */
	RealTimeStamp & setMax();
	/** @brief Set this stamp to minimum (Epoch) */
	RealTimeStamp & setMin();

	/** @brief Set time stamp from current time.
	 *
	 * @returns Reference to itself
	 */
	RealTimeStamp & stamp();

	/** @brief Get seconds since Epoch. */
	long int getSec() const;
	/** @brief Get micro seconds since Epoch+sec. */
	long int getUSec() const;
	/** @brief Get seconds (since Epoch) as real number (including micro seconds). */
	long double getSeconds() const;

	/** @brief Standard == operator. */
	bool operator == (RealTimeStamp const & rt) const;
	/** @brief Standard < operator. */
	bool operator < (RealTimeStamp const & rt) const;
	/** @brief Standard <= operator. */
	bool operator <= (RealTimeStamp const & rt) const;
	/** @brief Standard += operator. */
	RealTimeStamp & operator += (RealTimeStamp const & rt);
	/** @brief Standard + operator. */
	RealTimeStamp operator + (RealTimeStamp const & rt) const;
	/** @brief Standard -= operator. */
	RealTimeStamp & operator -= (RealTimeStamp const & rt);
	/** @brief Standard - operator. */
	RealTimeStamp operator - (RealTimeStamp const & rt) const;

private:
	long int sec_;
	long int usec_;
	static long int const tenExpSix_;

	void normalize();
};

/** @brief Streaming operator for RealTimeStamp. */
std::ostream & operator << (std::ostream & os, RealTimeStamp const & rt);

/** @brief Log time used for a scope.
 *
 * - Usage as-is: Automatic logging to out stream (nothing if NULL).
 * - Usage custom logging: Derive class, add custom logging to derived class' destructor, construct w/ out=0.
 */
class ScopeRealTime: private RealTimeStamp
{
private:
	std::ostream * const out_;
public:
	ScopeRealTime(std::ostream * const out);
	~ScopeRealTime();
	RealTimeStamp get() const;
};

}}
#endif
