// -*- C++ -*-
// TAO_Time_Service_Clerk.cpp,v 1.25 2003/11/05 03:59:58 dhinton Exp

#include "TAO_Time_Service_Clerk.h"
#include "TAO_TIO.h"
#include "TAO_UTO.h"

#include "tao/ORB_Core.h"
#include "ace/OS_NS_sys_time.h"

// Constructor.
TAO_Time_Service_Clerk::TAO_Time_Service_Clerk (int timer_value,
                                                int timer_value_usecs,
                                                const IORS& servers)
  : server_ (servers),
    helper_ (this)
{
  // Schedule the helper to be invoked by the reactor
  // periodically.

  if (TAO_ORB_Core_instance ()->reactor ()->schedule_timer
      (&helper_,
       0,
       ACE_Time_Value::zero,
       ACE_Time_Value(timer_value,timer_value_usecs)) == -1)
    ACE_ERROR ((LM_ERROR,
                "%p\n",
                "schedule_timer ()"));
}

// Destructor.

TAO_Time_Service_Clerk::~TAO_Time_Service_Clerk (void)
{
}

// This method returns the global time and an estimate of inaccuracy
// in a UTO.

CosTime::UTO_ptr
TAO_Time_Service_Clerk::universal_time (ACE_ENV_SINGLE_ARG_DECL)
    ACE_THROW_SPEC ((CORBA::SystemException,
                     CosTime::TimeUnavailable))
{
  TAO_UTO *uto = 0;

  ACE_NEW_THROW_EX (uto,
                    TAO_UTO (this->get_time (),
                             this->inaccuracy (),
                             this->time_displacement_factor ()),
                    CORBA::NO_MEMORY ());
  ACE_CHECK_RETURN (CosTime::UTO::_nil ());
  // Return the global time as a UTO.

  return uto->_this (ACE_ENV_SINGLE_ARG_PARAMETER);
}

// This method returns the global time in a UTO only if the time can
// be guaranteed to have been obtained securely.  This method is not
// implemented currently.

CosTime::UTO_ptr
TAO_Time_Service_Clerk::secure_universal_time (ACE_ENV_SINGLE_ARG_DECL)
    ACE_THROW_SPEC ((CORBA::SystemException,
                     CosTime::TimeUnavailable))
{
  ACE_THROW_RETURN (CORBA::NO_IMPLEMENT (),
                    CosTime::UTO::_nil ());
}

// This creates a new UTO based on the given parameters.

CosTime::UTO_ptr
TAO_Time_Service_Clerk::new_universal_time (TimeBase::TimeT time,
                                            TimeBase::InaccuracyT inaccuracy,
                                            TimeBase::TdfT tdf
                                            ACE_ENV_ARG_DECL)
    ACE_THROW_SPEC ((CORBA::SystemException))
{
  TAO_UTO *uto = 0;

  ACE_NEW_THROW_EX (uto,
                    TAO_UTO (time,
                             inaccuracy,
                             tdf),
                    CORBA::NO_MEMORY ());
  ACE_CHECK_RETURN (CosTime::UTO::_nil ());

  return uto->_this (ACE_ENV_SINGLE_ARG_PARAMETER);
}

// This creates a new UTO given a time in the UtcT form.

CosTime::UTO_ptr
TAO_Time_Service_Clerk::uto_from_utc (const TimeBase::UtcT &utc
                                      ACE_ENV_ARG_DECL)
    ACE_THROW_SPEC ((CORBA::SystemException))
{
  TAO_UTO *uto = 0;

  // Use the low and high values of inaccuracy
  // to calculate the total inaccuracy.

  TimeBase::InaccuracyT inaccuracy = utc.inacchi;
  inaccuracy <<= 32;
  inaccuracy |= utc.inacclo;

  ACE_NEW_THROW_EX (uto,
                    TAO_UTO (utc.time,
                             inaccuracy,
                             utc.tdf),
                    CORBA::NO_MEMORY ());
  ACE_CHECK_RETURN (CosTime::UTO::_nil ());
  return uto->_this (ACE_ENV_SINGLE_ARG_PARAMETER);
}

// This creates a new TIO with the given parameters.

CosTime::TIO_ptr
TAO_Time_Service_Clerk::new_interval (TimeBase::TimeT lower,
                                      TimeBase::TimeT upper
                                      ACE_ENV_ARG_DECL)
    ACE_THROW_SPEC ((CORBA::SystemException))
{
  TAO_TIO *tio = 0;

  ACE_NEW_THROW_EX (tio,
                    TAO_TIO (lower,
                             upper),
                    CORBA::NO_MEMORY ());
  ACE_CHECK_RETURN (CosTime::TIO::_nil ());
  return tio->_this (ACE_ENV_SINGLE_ARG_PARAMETER);
}

CORBA::ULongLong
TAO_Time_Service_Clerk::get_time (void)
{
  // Globally sync. time is the latest global time plus the time
  // elapsed since last updation was done.

  const ACE_Time_Value timeofday = ACE_OS::gettimeofday ();

  return (CORBA::ULongLong) (ACE_static_cast (CORBA::ULongLong,
                                              timeofday.sec ()) *
                             ACE_static_cast (ACE_UINT32,
                                              10000000) +
                             ACE_static_cast (CORBA::ULongLong,
                                              timeofday.usec () * 10))
    - this->update_timestamp_
    + this->time_;
}

// Returns the time displacement factor in minutes.
// This is displacement from the GMT.
CORBA::Short
TAO_Time_Service_Clerk::time_displacement_factor (void)
{
  return time_displacement_factor_;
}

// Sets the TDF.
void
TAO_Time_Service_Clerk::time_displacement_factor (CORBA::Short tdf)
{
  this->time_displacement_factor_ = tdf;
}

// GET method for inaccuracy.
TimeBase::InaccuracyT
TAO_Time_Service_Clerk::inaccuracy (void)
{
  return this->inaccuracy_;
}

// SET method for inaccuracy.
void
TAO_Time_Service_Clerk::inaccuracy (TimeBase::InaccuracyT inaccuracy)
{
  this->inaccuracy_ = inaccuracy;
}
