/* AXPbox Alpha Emulator
 * Copyright (C) 2020 Tomáš Glozar
 * Website: https://github.com/lenticularis39/axpbox
 *
 * 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.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * Although this is not required, the author would appreciate being notified of,
 * and receiving any modifications you may make to the source code that might
 * serve the general public.
 *
 * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)
 * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.
 */

//
// Timestamp.h
//
// $Id: Timestamp.h,v 1.1 2008/05/31 15:47:29 iamcamiel Exp $
//
// Library: Foundation
// Package: DateTime
// Module:  Timestamp
//
// Definition of the Timestamp class.
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

#ifndef Foundation_Timestamp_INCLUDED
#define Foundation_Timestamp_INCLUDED

#include "Foundation.hpp"
#include <ctime>

class CTimestamp
/// A Timestamp stores a monotonic time value
/// with (theoretical) microseconds resolution.
/// Timestamps can be compared with each other
/// and simple arithmetics are supported.
/// Timestamps are UTC (Coordinated Universal Time)
/// based and thus independent of the timezone
/// in effect on the system.
{
public:
  typedef Int64 TimeVal; /// monotonic UTC time value in microsecond resolution
  typedef Int64
      UtcTimeVal; /// monotonic UTC time value in 100 nanosecond resolution
  typedef Int64 TimeDiff; /// difference between two timestamps in microseconds

  CTimestamp();
  /// Creates a timestamp with the current time.

  CTimestamp(TimeVal tv);
  /// Creates a timestamp from the given time value.

  CTimestamp(const CTimestamp &other);
  /// Copy constructor.

  ~CTimestamp();
  /// Destroys the timestamp

  CTimestamp &operator=(const CTimestamp &other);
  CTimestamp &operator=(TimeVal tv);

  void swap(CTimestamp &timestamp);
  /// Swaps the Timestamp with another one.

  void update();
  /// Updates the Timestamp with the current time.

  bool operator==(const CTimestamp &ts) const;
  bool operator!=(const CTimestamp &ts) const;
  bool operator>(const CTimestamp &ts) const;
  bool operator>=(const CTimestamp &ts) const;
  bool operator<(const CTimestamp &ts) const;
  bool operator<=(const CTimestamp &ts) const;

  CTimestamp operator+(TimeDiff d) const;
  CTimestamp operator-(TimeDiff d) const;
  TimeDiff operator-(const CTimestamp &ts) const;
  CTimestamp &operator+=(TimeDiff d);
  CTimestamp &operator-=(TimeDiff d);

  std::time_t epochTime() const;
  /// Returns the timestamp expressed in time_t.
  /// time_t base time is midnight, January 1, 1970.
  /// Resolution is one second.

  UtcTimeVal utcTime() const;
  /// Returns the timestamp expressed in UTC-based
  /// time. UTC base time is midnight, October 15, 1582.
  /// Resolution is 100 nanoseconds.

  TimeVal epochMicroseconds() const;
  /// Returns the timestamp expressed in microseconds
  /// since the Unix epoch, midnight, January 1, 1970.

  TimeDiff elapsed() const;
  /// Returns the time elapsed since the time denoted by
  /// the timestamp. Equivalent to Timestamp() - *this.

  bool isElapsed(TimeDiff interval) const;
  /// Returns true iff the given interval has passed
  /// since the time denoted by the timestamp.

  static CTimestamp fromEpochTime(std::time_t t);
  /// Creates a timestamp from a std::time_t.

  static CTimestamp fromUtcTime(UtcTimeVal val);
  /// Creates a timestamp from a UTC time value.

  static TimeVal resolution();
  /// Returns the resolution in units per second.
  /// Since the timestamp has microsecond resolution,
  /// the returned value is always 1000000.

#if defined(_WIN32)
  static CTimestamp fromFileTimeNP(UInt32 fileTimeLow, UInt32 fileTimeHigh);
  void toFileTimeNP(UInt32 &fileTimeLow, UInt32 &fileTimeHigh) const;
#endif

private:
  TimeVal _ts;
};

//
// inlines
//
inline bool CTimestamp::operator==(const CTimestamp &ts) const {
  return _ts == ts._ts;
}

inline bool CTimestamp::operator!=(const CTimestamp &ts) const {
  return _ts != ts._ts;
}

inline bool CTimestamp::operator>(const CTimestamp &ts) const {
  return _ts > ts._ts;
}

inline bool CTimestamp::operator>=(const CTimestamp &ts) const {
  return _ts >= ts._ts;
}

inline bool CTimestamp::operator<(const CTimestamp &ts) const {
  return _ts < ts._ts;
}

inline bool CTimestamp::operator<=(const CTimestamp &ts) const {
  return _ts <= ts._ts;
}

inline CTimestamp CTimestamp::operator+(CTimestamp::TimeDiff d) const {
  return CTimestamp(_ts + d);
}

inline CTimestamp CTimestamp::operator-(CTimestamp::TimeDiff d) const {
  return CTimestamp(_ts - d);
}

inline CTimestamp::TimeDiff CTimestamp::operator-(const CTimestamp &ts) const {
  return _ts - ts._ts;
}

inline CTimestamp &CTimestamp::operator+=(CTimestamp::TimeDiff d) {
  _ts += d;
  return *this;
}

inline CTimestamp &CTimestamp::operator-=(CTimestamp::TimeDiff d) {
  _ts -= d;
  return *this;
}

inline std::time_t CTimestamp::epochTime() const {
  return std::time_t(_ts / resolution());
}

inline CTimestamp::UtcTimeVal CTimestamp::utcTime() const {
  return _ts * 10 + (TimeDiff(0x01b21dd2) << 32) + 0x13814000;
}

inline CTimestamp::TimeVal CTimestamp::epochMicroseconds() const { return _ts; }

inline CTimestamp::TimeDiff CTimestamp::elapsed() const {
  CTimestamp now;
  return now - *this;
}

inline bool CTimestamp::isElapsed(CTimestamp::TimeDiff interval) const {
  CTimestamp now;
  CTimestamp::TimeDiff diff = now - *this;
  return diff >= interval;
}

inline CTimestamp::TimeVal CTimestamp::resolution() { return 1000000; }

inline void swap(CTimestamp &s1, CTimestamp &s2) { s1.swap(s2); }

#endif // Foundation_Timestamp_INCLUDED
