/*!
  \file
  \brief スケジューラの動作サンプル

  \author Satofumi KAMIMURA

  $Id: SchedulerModel.cpp 1053 2009-06-20 22:52:51Z satofumi $
*/

#include "ManagedTicks.h"
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <iostream>

using namespace qrk;
using namespace std;


namespace
{
  enum {
    MaxLoopTimes = 100,
  };

  QMutex* mutex_ = NULL;


  class EventScheduler : public QThread
  {
    long current_ticks_;
    ManagedTicks timer_;

    long wakeup_ticks_;         // delay() が起床される時刻
    QWaitCondition* wait_condition_;



  public:
    EventScheduler(void)
      : current_ticks_(0), wakeup_ticks_(0), wait_condition_(NULL)
    {
      timer_.play();
    }


    void run(void)
    {
      while (1) {
        mutex_->lock();

        // システム時刻を取得
        long target_ticks = timer_.ticks();
        int loop_times = min(target_ticks - current_ticks_,
                             static_cast<long>(MaxLoopTimes));

        for (int i = 0; i < loop_times; ++i) {
          // その時刻にイベント・リストに登録されているタスクがあれば、処理
          // !!! シミュレータの呼び出し

          // delay() の起床
          if (wait_condition_ && (current_ticks_ >= wakeup_ticks_)) {
            wait_condition_->wakeOne();
            wait_condition_ = NULL;
          }

          ++current_ticks_;
        }

        mutex_->unlock();

        // system_getTicks() の代わり
        QThread::msleep(1);
      }
    }


    long getTicks(void)
    {
      mutex_->lock();
      long ticks = current_ticks_;
      mutex_->unlock();

      return ticks;
    }


    void setDelayTicks(int msec, QWaitCondition* condition)
    {
      mutex_->lock();
      wakeup_ticks_ = current_ticks_ + msec;
      wait_condition_ = condition;
      mutex_->unlock();
    }
  };


  EventScheduler* event_scheduler_ = NULL;


  long getTicks(void)
  {
    return event_scheduler_->getTicks();
  }


  void delay(int msec)
  {
    QWaitCondition condition;
    QMutex mutex;
    event_scheduler_->setDelayTicks(msec, &condition);
    condition.wait(&mutex);
  }
}


int main(int argc, char *argv[])
{
  static_cast<void>(argc);
  static_cast<void>(argv);

  mutex_ = new QMutex;

  event_scheduler_ = new EventScheduler;
  event_scheduler_->start();

  // プログラム例
  for (int i = 0; i < 10; ++i) {
    cout << getTicks() << " [msec]" << endl;
    delay(100);
  }

  event_scheduler_->terminate();
  event_scheduler_->wait();
  delete event_scheduler_;
  delete mutex_;

  return 0;
}
