/*
  モジュールの時刻同期管理インターフェース
  Satofumi KAMIMURA
  $Id: ticksCtrlInterface.cpp 286 2008-10-20 09:40:22Z satofumi $
*/

#include "ticksCtrlInterface.h"
#include "coordinateCtrl.h"


unsigned long TicksCtrlInterface::getModuleTicks(unsigned long rawTicks) {
  ticksInfo_t& ticksInfo = getTicksInfo();

  return (rawTicks - ticksInfo.moduleDiff) + ticksInfo.setDiff;
}


unsigned long TicksCtrlInterface::getModuleTicks(void) {
  unsigned long begin_before = getHostTicks();
  beginTimeAdjust();
  unsigned long begin_after = getHostTicks();

  unsigned long ticks = getModuleTicks(getModuleRawTicks());
  endTimeAdjust();

  return ticks - (begin_after - begin_before);
}


void TicksCtrlInterface::adjustOwnTicks(unsigned long setTicks) {
  unsigned long beginHostTicks = getHostTicks();
  ticksInfo_t& ticksInfo = getTicksInfo();

  // モジュール時刻印の調整開始
  beginTimeAdjust();

  // 通信遅延の評価
  int tryTimes = 1 << ticksInfo.tryTimes_shift;
  unsigned long transTicks_total = 0;
  unsigned long module_ticks = 0;
  unsigned long sendTicks = getHostTicks();
  unsigned long recvTicks = 0;
  for (int i = 0; i < tryTimes; ++i) {
    module_ticks = getModuleRawTicks();
    recvTicks = getHostTicks();
    transTicks_total += recvTicks - sendTicks;

    sendTicks = recvTicks;
  }
  // モジュール時刻印の調整終了
  endTimeAdjust();

  unsigned long recvAVG = transTicks_total >> (ticksInfo.tryTimes_shift +1);
  ticksInfo.moduleDiff = (module_ticks + recvAVG) - recvTicks;

  // ホスト時刻印の調整
  ticksInfo.setDiff = setTicks - beginHostTicks;
}


void TicksCtrlInterface::adjustChildCrdsTicks(TicksCtrlInterface* root,
					      long hostDiff,
					      CoordinateCtrl* subRoot) {

  for (std::list<CoordinateCtrl*>::iterator it =
	 subRoot->getChildCrd().begin();
       it != subRoot->getChildCrd().end(); ++it) {
    TicksCtrlInterface* obj = dynamic_cast<TicksCtrlInterface*>(*it);
    if (obj) {
      obj->adjustOwnTicks(root->getHostTicks() - hostDiff);
    }
  }

  // 子座標系について再帰呼び出し
  for (std::list<CoordinateCtrl*>::iterator it =
	 subRoot->getChildCrd().begin();
       it != subRoot->getChildCrd().end(); ++it) {
    TicksCtrlInterface* obj = dynamic_cast<TicksCtrlInterface*>(*it);
    if (obj) {
      obj->adjustChildCrdsTicks(root, hostDiff, *it);
    }
  }
}


void TicksCtrlInterface::adjustSubTreeTicks(unsigned long setTicks) {
  CoordinateCtrl* root = dynamic_cast<CoordinateCtrl*>(this);
  if (!root) {
    return;
  }
  long hostDiff = getHostTicks() - setTicks;

  // 時刻印の同期処理
  adjustOwnTicks(setTicks);
  adjustChildCrdsTicks(this, hostDiff, root);
}
