/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM 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; only version 2 of the License.      
 * 
 * NMM 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 NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#ifndef NMM_TIME_HPP
#define NMM_TIME_HPP NMM_TIME_HPP

#include "nmm/nmm_prefix.hpp"

#include <iosfwd>
#include <string>

#include <nmm/nmm_types.hpp>
#include "nmm_timeval.hpp"

#include "visibility.hpp"

namespace NMM {
  
  class Rational;
  class Interval;
  
  //! This class represents a point in time.
  /*! 
   *  Time is represented with a precision of nanoseconds.
   *  A time value can range over about 68 years in the past and 
   *  in the future.
   *  Time is internally stored in two nmm_int64's (one for the seconds and
   *  one for the nanoseconds.) It is important to notice that the
   *  nanoseconds are always between 0 and 10^9 - 1, and that the value of the Interval
   *  must be calculated as seconds + nanoseconds/nano_per_sec. So, e.g. -0.2 sec
   *  is stored as -1 second, 800,000,000 nanoseconds.
   */
  class DLLEXPORT Time {
  public:
    nmm_int64 sec;     //!< The seconds.
    nmm_int64 nsec;    //!< The nanoseconds.

    //! The main constructor.
    /*! 
     *  \return A time object that is initialized to zero.
     */
    explicit Time();

    //! This constructor initializes the time object to a given value.
    /*! 
     *  \param nanoseconds The time value represented as nanoseconds.
     */
    explicit Time(const nmm_int64& nanoseconds);

    //! This constructor initializes the time object to a given value.
    /*!
     *  \param seconds The seconds of the new time object.
     *  \param nanoseconds The nanoseconds of the new time object.
     */
    explicit Time(const nmm_int64& seconds, const nmm_int64& nanoseconds);

    //! This constructor initializes the time object to a given value.
    /*!
     *  \param time The time value represented as a struct timeval.
     */
    Time(const struct timeval& time);

    //! This constructor initializes the time object to a given value.
    /*!
     *  \param time The time value represented as a rational number.
     *         (Where 1 represents one second.)
     */
    explicit Time(const Rational& time);

    //! Adds an interval to a time.
    //! 
    //! @param interval that is added
    //! @return Time including the result
    Time& operator+=(const Interval& interval);

    //! Subtracts an interval from a time.
    //! 
    //! @param interval that is subtracted
    //! @return Time including the result
    Time& operator-=(const Interval& interval);

    //! Get Time in format: "sec.nsec", where nsec are properly filled with
    //! '0' up to 9 digits
    //!
    //! @return string including the time 
    std::string getPrettyString() const;
  };

  //! Adds an interval to a time and returns the result as new time 
  //! object.
  //! 
  //! @param a first summand
  //! @param b second summand
  //! @return Time including the result 
  DLLEXPORT Time operator+(const Time& a, const Interval& b);

  //! Subtracts an interval from a time and returns the result as 
  //! new time object.
  //! 
  //! @param a specifies minuend
  //! @param b specifies subtrahend
  //! @return Time including the result 
  DLLEXPORT Time operator-(const Time& a, const Interval& b);

  //! Returns true iff the two times are equal.
  //! 
  //! @param a first Time
  //! @param b second Time
  //! @return true iff the two times are equal.
  inline bool operator==(const Time& a, const Time& b)
  {
    return a.sec == b.sec && a.nsec == b.nsec;
  };

  //! Returns true iff the two times are not equal.
  //! 
  //! @param a first Time
  //! @param b second Time
  //! @return true iff the two times are not equal.
  inline bool operator!=(const Time& a, const Time& b)
  {
    return a.sec != b.sec || a.nsec != b.nsec;
  };

  //! Returns true iff a is less than b.
  //! 
  //! @param a first Time
  //! @param b second Time
  //! @return true iff a is less than b.
  inline bool operator<(const Time& a, const Time& b)
  {
    return (a.sec < b.sec || (a.sec == b.sec && a.nsec < b.nsec));
  };

  //! Returns true iff a is less than or equal to b.
  //! 
  //! @param a first Time
  //! @param b second Time
  //! @return true iff a is less than or equal to b.
  inline bool operator<=(const Time& a, const Time& b)
  {
    return (a.sec < b.sec || (a.sec == b.sec && a.nsec <= b.nsec));
  };

  //! Returns true iff a is greater than b.
  //! 
  //! @param a first Time
  //! @param b second Time
  //! @return true iff a is greater than b.
  inline bool operator>(const Time& a, const Time& b)
  {
    return (a.sec > b.sec || (a.sec == b.sec && a.nsec > b.nsec));
  };

  //! Returns true iff a is greater than or equal to b.
  //! 
  //! @param a first Time
  //! @param b second Time
  //! @return true iff a is greater than or equal to b.
  inline bool operator>=(const Time& a, const Time& b)
  {
    return (a.sec > b.sec || (a.sec == b.sec && a.nsec >= b.nsec));
  };

  //! Returns an output stream that represents the time value.
  /*! The output should be human readable, and the internal representation can be
   *  confusing when having negative values. E.g. -0.2 sec
   *  is stored as -1 second, 800,000,000 nanoseconds. The output operator
   *  calculates a human readable output from the internal representation.
   * 
   * @param s outupt stream that is used to write time
   * @param time Time that is written to s 
   */
  DLLEXPORT std::ostream& operator<<(std::ostream& s, const Time& time);
}

#include "nmm/nmm_suffix.hpp"

#endif // _NMM_TIME_HPP_
