#include "updater.hpp"

// time 
#include <time.h>

#include <string>

#include <iostream>

Updater& Updater::get_instance() 
{
  static Updater s;
  return s;
}

Updater::Updater() 
  : progressbar(Overlay("progressbar")), status_progressbar(0), 
    total_progressbar(0), header(""), running(false)
{}

void Updater::activate()
{
  running = true;
}

void Updater::deactivate()
{
  running = false;
}

void Updater::run()
{
  while (true)
    {
      while (!running)
	sleep(500); // ms

      timer.elements_mut.enterMutex();

      gettimeofday(&timer.current_time, NULL);

      for (std::list<TimeElement>::iterator iter = timer.elements.begin(), end = timer.elements.end();
           iter != end; ++iter)
        if (iter->active) {

          if (iter->next_time.tv_sec < timer.current_time.tv_sec || 
              (iter->next_time.tv_sec == timer.current_time.tv_sec && iter->next_time.tv_usec <= timer.current_time.tv_usec)) {
            iter->call_back_f->call();

	    iter->next_time.tv_sec = timer.current_time.tv_sec + iter->time_f->call()/1000;
	    iter->next_time.tv_usec = timer.current_time.tv_usec + ((iter->time_f->call() - ((iter->time_f->call()/1000)*1000))*1000);

	    if (iter->next_time.tv_usec > 1000*1000) {
	      iter->next_time.tv_sec += 1;
	      iter->next_time.tv_usec -= 1000*1000;
	    }
          }
        }

      timer.elements_mut.leaveMutex();

      sleep(200); // ms
    }
}

void Updater::Timer::add(TimeElement te)
{
  elements_mut.enterMutex();

  gettimeofday(&current_time, NULL);
  te.next_time.tv_sec = current_time.tv_sec + te.time_f->call()/1000;
  te.next_time.tv_usec = current_time.tv_usec + ((te.time_f->call() - ((te.time_f->call()/1000)*1000))*1000);

  if (te.next_time.tv_usec > 1000*1000) {
    te.next_time.tv_sec += 1;
    te.next_time.tv_usec -= 1000*1000;
  }
  elements.push_back(te);

  elements_mut.leaveMutex();
}

void Updater::Timer::del(std::string name)
{
  elements_mut.enterMutex();

  for (std::list<TimeElement>::iterator iter = elements.begin(), end = elements.end();
       iter != end; ++iter)
    if (iter->name == name) {
      elements.erase(iter);
      break;
    }

  elements_mut.leaveMutex();
}

void Updater::Timer::activate(const std::string& name)
{
  elements_mut.enterMutex();

  for (std::list<TimeElement>::iterator iter = elements.begin(), end = elements.end();
       iter != end; ++iter)
    if (iter->name == name) {
      gettimeofday(&current_time, NULL);
      iter->next_time.tv_sec = current_time.tv_sec + iter->time_f->call()/1000;
      iter->next_time.tv_usec = current_time.tv_usec + (iter->time_f->call() - (iter->next_time.tv_sec*1000)) * 1000;
      iter->active = true;
      break;
    }

  elements_mut.leaveMutex();
}

void Updater::Timer::deactivate(const std::string& name)
{
  elements_mut.enterMutex();

  for (std::list<TimeElement>::iterator iter = elements.begin(), end = elements.end();
       iter != end; ++iter)
    if (iter->name == name) {
      iter->active = false;
      break;
    }

  elements_mut.leaveMutex();
}

bool Updater::Timer::status(const std::string& name)
{
  elements_mut.enterMutex();

  bool active_element = false;
  for (std::list<TimeElement>::iterator iter = elements.begin(), end = elements.end();
       iter != end; ++iter)
    if (iter->name == name) {
      active_element = iter->active;
      break;
    }

  elements_mut.leaveMutex();

  return active_element;
}
