#include "tmultiplex.h"
#include <api/timer/timerclient.h>
#include <assert.h>
VirtualTimer::VirtualTimer(TimerClient *_client, intptr_t _id, api_dependent *depend) :
  client(_client), id(_id), dep(depend)
{
  name = client->timerclient_getName();
  mclient = client->timerclient_getMasterClient();
}

MainTimerMultiplexer::MainTimerMultiplexer() {
  setClient(this);
}

MainTimerMultiplexer::~MainTimerMultiplexer() {
/*
  foreach(timerclients)
    VirtualTimer *vt = timerclients.getfor();
    //DebugString("TIMER MULTIPLEXER WARNING: TimerClient %X (%s) was not deregistered\n", vt->client, vt->name.getValue());
  endfor;  
*/
// NOTE: if you get a crash here, someone probably had a timer event outstanding
// or didn't call down in timerclient_timerCallback()

// Also this is guaranteed to happen if one of your timerclient objects (ie: a wnd) was not deleted
// eventho your DLL has been unloaded. the watched pointer will remain watched instead of unregistering
// itself from its viewers. DependentViewerI (one of our direct ancestors) will try to dereference that pointer in
// order to signal it that a viewer was detached, and it will crash.

  timerclients.deleteAll();
}

void MainTimerMultiplexer::add(TimerClient *client, intptr_t id, int ms) {
  remove(client, id);
  api_dependent *d = client->timerclient_getDependencyPtr();
  assert(d != NULL);
  VirtualTimer *t = new VirtualTimer(client, id, d);
  timerclients.addItem(t);
  viewer_addViewItem(d);
  if (t->mclient) {
    d = t->mclient->timerclient_getDependencyPtr();
    ASSERT(d != NULL);
    viewer_addViewItem(d);
  }
  addTimer(ms, static_cast<void *>(t));
}

void MainTimerMultiplexer::remove(TimerClient *client, intptr_t id) {
  while (masters.haveItem(client)) masters.removeItem(client);
  for (int i=0;i<timerclients.getNumItems();i++) {
    VirtualTimer *t = timerclients.enumItem(i);
    masters.removeItem(t->mclient);//BU store mclient on VirtualTimer now
    if (t->client == client && (t->id == id || id == -1)) {
      viewer_delViewItem(t->dep);
      timerclients.removeByPos(i);
      removeTimer(static_cast<void *>(t));
      delete t;
      i--;
    }
  }
}

int MainTimerMultiplexer::isValidTimerClientPtr(TimerClient *tc, api_dependent *dep) {
//   try {
  __try {
      api_dependent *d = tc->timerclient_getDependencyPtr();
      if (d != dep) return 0;
   //} catch (...) {
  } __except (1) {
     return 0;
   } 
   return 1;
}

void MainTimerMultiplexer::onMultiplexedTimer(void *data, int skip, int mssincelasttimer) {
  assert(data != NULL);
  VirtualTimer *t = static_cast<VirtualTimer *>(data);
  if (!isValidTimerClientPtr(t->client, t->dep)) {
    //DebugString("TIMER MULTIPLEXER WARNING: TimerClient %X (%s) is no longer valid! (%d)\n", t->client, t->name.getValue(), t->id);
    remove(t->client, -1);
	t->client = 0;
  } else {
    TimerClient *mc = t->client->timerclient_getMasterClient();
    if (mc) masters.addItem(mc);
    t->client->timerclient_setSkipped(skip);
    t->client->timerclient_setTimerDelay(mssincelasttimer);
    t->client->timerclient_timerCallback(t->id); 
    // -----------------------------------------------------------------------
    // WARNING
    // 
    // below this line, you can no longer assume that t is pointing at valid
    // memory, because timerCallback can eventually call remove
    // -----------------------------------------------------------------------
  } 
}

void MainTimerMultiplexer::onServerTimer() {
  TimerMultiplexer::onServerTimer();
  TimerClient *last = NULL;
  for (int i=0;i<masters.getNumItems();i++) {
    TimerClient *t = masters.enumItem(i);
    if (t == last) continue;
    t->timerclient_onMasterClientMultiplex();
    last = t;
  }
  masters.removeAll();
}

int MainTimerMultiplexer::haveClient(TimerClient *client) {
  for (int i=0;i<timerclients.getNumItems();i++) 
	{
		VirtualTimer *vt = timerclients.enumItem(i);
		if (vt && vt->client == client)
			return 1;
	}
  return 0;
}

int MainTimerMultiplexer::viewer_onItemDeleted(api_dependent *item) {
  for (int i=0;i<timerclients.getNumItems();i++) {
    VirtualTimer *vt = timerclients.enumItem(i);
    if (vt->dep == item) {
      remove(vt->client, -1);
      return 1;
    }
  }
  return 1;
}