/*!
  \file
  \brief 時間経過の管理クラス

  \author Satofumi KAMIMURA

  $Id: ManagedTicks.cpp 1422 2009-10-18 13:48:05Z satofumi $
*/

#include "ManagedTicks.h"
#include "ticks.h"
#include <boost/function.hpp>

using namespace qrk;
using namespace boost;


struct ManagedTicks::pImpl
{
  enum {
    InvalidTicks = -1,
  };
  TicksFunction ticks_function_;
  double speed_rate_;
  long elapsed_msec_;
  bool is_playing_;
  long last_ticks_;


  pImpl(void)
    : ticks_function_(qrk::ticks),
      speed_rate_(1.0), elapsed_msec_(0), is_playing_(false),
      last_ticks_(InvalidTicks)
  {
  }


  void restart(void)
  {
    last_ticks_ = ticks_function_();
  }


  void updateElapsed(void)
  {
    elapsed_msec_ +=
      static_cast<long>((ticks_function_() - last_ticks_) * speed_rate_);
  }


  long ticks(void) const
  {
    long ticks = elapsed_msec_;
    if (is_playing_) {
      ticks +=
        static_cast<long>((ticks_function_() - last_ticks_) * speed_rate_);
    }
    return ticks;
  }


  void play(void)
  {
    if (is_playing_) {
      updateElapsed();
      speed_rate_ = 1.0;
    }

    resume();
  }


  void pause(void)
  {
    if (! is_playing_) {
      return;
    }
    updateElapsed();
    is_playing_ = false;
  }


  void resume(void)
  {
    is_playing_ = true;
    restart();
  }


  void moreFaster(void)
  {
    if (is_playing_) {
      updateElapsed();
    }
    speed_rate_ *= 2.0;
    restart();
  }


  void moreSlower(void)
  {
    if (is_playing_) {
      updateElapsed();
    }
    speed_rate_ /= 2.0;
    restart();
  }
};


ManagedTicks::ManagedTicks(void) : pimpl(new pImpl)
{
}


ManagedTicks::~ManagedTicks(void)
{
}


void ManagedTicks::setTicksFunction(TicksFunction function)
{
  pimpl->ticks_function_ = function;
}


long ManagedTicks::ticks(void) const
{
  return pimpl->ticks();
}


void ManagedTicks::play(void)
{
  if (pimpl->last_ticks_ == pImpl::InvalidTicks) {
    pimpl->last_ticks_ = pimpl->ticks_function_();
  }
  pimpl->play();
}


void ManagedTicks::pause(void)
{
  pimpl->pause();
}


void ManagedTicks::resume(void)
{
  pimpl->resume();
}


void ManagedTicks::moreFaster(void)
{
  pimpl->moreFaster();
}


void ManagedTicks::moreSlower(void)
{
  pimpl->moreSlower();
}
