/* TimeSensor.C: TimeSensor nodes (public source) */

#include "TimeSensor.H"
#include "renderer.H"
#include "nodeInterface.H"

namespace xrml {

void TimeSensor::util_init(void)
{
  isActive = false;  // default value
  current_cycle = previous_cycle = -1.;
  fraction = 0.;
  waiting_to_become_active = true;
}

bool TimeSensor::new_cycle(void)
{
  return (previous_cycle < current_cycle);
}

bool TimeSensor::should_be_active(void)
{
  // determines whether the node shall be active or inactive at the
  // current time
  if (enabled == false)
    return false;
  else if (isActive && new_cycle() && loop == false)
    return false;
  else if (world->time < startTime)
    return false;
  else if (waiting_to_become_active)
    return true;
  else if (startTime < stopTime)
    return (world->time < stopTime);
  else
    return (loop == true);
}

void TimeSensor::set_cycle(double time)
{
  double cycle = (time - startTime) / cycleInterval;
  current_cycle = floor(cycle);
  fraction = cycle - current_cycle;
}

double TimeSensor::cycle_start_time(void)
{
  return startTime + cycleInterval * current_cycle;
}

void TimeSensor::sample(void)
{
  // generates regular sample outputs for the current time
  if (enabled == false)
    return;

  if (new_cycle())
    // time at beginning of the current cycle
    post_cycleTime(cycle_start_time());

  post_time(world->time);
  post_fraction_changed(fraction==0.0 && world->time>startTime ? 1.0 : fraction);
}

void TimeSensor::activate(void)
{
  // activate inactive time sensor
  waiting_to_become_active = false;
  post_isActive(true);
  set_cycle(world->time);
  previous_cycle = current_cycle-1.; // make sure to generate cycleTime evet
  sample();
}

void TimeSensor::deactivate(void)
{
  // de-activates active time sensor
  double end_time = (current_cycle > 0. && loop == false) ? cycle_start_time() : (double)stopTime;
  if (end_time > stopTime) end_time = stopTime;
  set_cycle(end_time);

  post_time(end_time);
  post_fraction_changed(fraction==0.0 && end_time>startTime ? 1.0 : fraction);

  post_isActive(false);
  current_cycle = previous_cycle = -1.;
  fraction = 0.;
}

bool TimeSensor::assign_cycleInterval(const SFTime& value)
{
  if (isActive)
    // ignore set_cycleInterval eventIns to active time sensor
    return false;

  cycleInterval = value;
  status |= cycleInterval_updated;
  timestamp = interface[0]->timestamp = world ? world->time : 0;
  return true;
}

bool TimeSensor::assign_startTime(const SFTime& value)
{
  if (isActive)
    // ignore set_startTime eventIns to active time sensor
    return false;

  waiting_to_become_active = true;
  startTime = value;
  status |= startTime_updated;
  timestamp = interface[3]->timestamp = world ? world->time : 0;
  return true;
}

bool TimeSensor::assign_stopTime(const SFTime& value)
{
  if (isActive) {
    if (stopTime <= startTime)
      return false;  // ignore such set_stopTime eventIns
    else if (stopTime <= world->time)
      deactivate();
  }

  stopTime = value;
  status |= stopTime_updated;
  timestamp = interface[4]->timestamp = world ? world->time : 0;
  return true;
}

void TimeSensor::render(void)
{
  if (cycleInterval < EPSILON) {
    Error(NULL, "%s.cycleInterval shall be greater than 0", name());
    cycleInterval = 1.;
  }
  if (isActive) {
    previous_cycle = current_cycle;
    set_cycle(world->time);
  }
  world->renderer->timeSensor(this);
}


}  // namespace xrml
