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

  \author Satofumi KAMIMURA

  $Id: ManagedTicks.cpp 1811 2010-04-30 16:12: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();
}
