/*
  coordinateCtrl.cpp のテスト
  Satofumi KAMIMURA
  $Id: CoordinateCtrlTest.cpp 351 2008-11-11 22:39:03Z satofumi $
*/

#include "CoordinateCtrlTest.h"
#include "typePrint.h"

using namespace VXV;

CPPUNIT_TEST_SUITE_REGISTRATION(CoordinateCtrlTest);
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CoordinateCtrlTest,"CoordinateCtrlTest");


void CoordinateCtrlTest::compileTest(void) {
  CoordinateCtrl crd;

  CoordinateCtrl *obj = new CoordinateCtrl();
  CPPUNIT_ASSERT(obj);
  delete obj;
}


void CoordinateCtrlTest::setParentCoordinate(void) {
  CoordinateCtrl* run = new CoordinateCtrl();
  CoordinateCtrl* hand = new CoordinateCtrl();
  hand->setOwnCrdToCrd(run);
  CoordinateCtrl urg;
  urg.setOwnCrdToCrd(hand);
  std::auto_ptr<CoordinateCtrl> urg2(new CoordinateCtrl());
  urg2->setOwnCrdToCrd(hand, Position(100, 0, Direction::deg(0)));

  Position3D expected = Position(100, 0, Direction::deg(0));
  CPPUNIT_ASSERT_EQUAL(expected, urg2->getCrdPosition());

  CPPUNIT_ASSERT_EQUAL(hand, urg.getParentCrd());
  CPPUNIT_ASSERT_EQUAL(run, hand->getParentCrd());
  //CPPUNIT_ASSERT_EQUAL(NULL, run->getParentCrd());

  delete hand;
  hand = NULL;

  CPPUNIT_ASSERT_EQUAL(run, urg.getParentCrd());
  CPPUNIT_ASSERT_EQUAL(run, urg2->getParentCrd());
  //CPPUNIT_ASSERT_EQUAL(NULL, run->getParentCrd());

  delete run;
  run = NULL;

  //CPPUNIT_ASSERT_EQUAL(NULL, urg.getParentCrd());
  //CPPUNIT_ASSERT_EQUAL(NULL, urg2->getParentCrd());
}


void CoordinateCtrlTest::adjustPositionTest(void) {
  // adjustPosition() ついてテスト
  CoordinateCtrl run;

  Position3D expected = Position();
  CPPUNIT_ASSERT_EQUAL(expected, run.getCrdPosition());

  run.adjustCrdPosition(Position(100, 100, Direction::deg(-90)));
  expected = Position(100, 100, Direction::deg(-90));
  CPPUNIT_ASSERT_EQUAL(expected, run.getCrdPosition());
}


void CoordinateCtrlTest::getOtherCrdPositionTest(void) {
  CoordinateCtrl run;
  CoordinateCtrl urg1;
  CoordinateCtrl urg2;
  urg1.setOwnCrdToCrd(&run, Position(100, 100, Direction::deg(90)));
  urg2.setOwnCrdToCrd(&run, Position(-100, -100, Direction::deg(90)));

  Position3D expected = Position(200, -200, Direction::deg(0));
  Position3D actual = urg1.getCrdPosition(&urg2);
  CPPUNIT_ASSERT_EQUAL(expected.x, actual.x);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(expected.y, actual.y, 1.0);
  CPPUNIT_ASSERT_EQUAL(expected.zt.to_deg(), actual.zt.to_deg());

  expected = Position(-200, 200, Direction::deg(0));
  actual = urg2.getCrdPosition(&urg1);
  CPPUNIT_ASSERT_EQUAL(expected.x, actual.x);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(expected.y, actual.y, 1.0);
  CPPUNIT_ASSERT_EQUAL(expected.zt.to_deg(), actual.zt.to_deg());
}


void CoordinateCtrlTest::getCrdPositionTest(void) {
  // 座標系を定義し、位置の取得テスト
  CoordinateCtrl run;
  CoordinateCtrl hand;
  hand.setOwnCrdToCrd(&run, Position(100, 100, Direction::deg(180)));
  CoordinateCtrl urg;
  urg.setOwnCrdToCrd(&hand, Position(100, 0, Direction::deg(90)));

  // Global 位置の取得
  Position3D expected = Position(0, 0, Direction::deg(0));
  CPPUNIT_ASSERT_EQUAL(expected, run.getCrdPosition());

  expected = Position(100, 100, Direction::deg(180));
  CPPUNIT_ASSERT_EQUAL(expected, hand.getCrdPosition());

  expected = Position(0, 100, Direction::deg(-90));
  CPPUNIT_ASSERT_EQUAL(expected, urg.getCrdPosition());

#if 0
  // Local 位置の取得
  expected = Position(0, 0, Direction::deg(0));
  CPPUNIT_ASSERT_EQUAL(expected, run.getCrdPosition(CoordinateCtrl::Local));
  CPPUNIT_ASSERT_EQUAL(expected, hand.getCrdPosition(CoordinateCtrl::Local));
  CPPUNIT_ASSERT_EQUAL(expected, urg.getCrdPosition(CoordinateCtrl::Local));
#endif

  // run における位置を取得
  expected = Position(0, 0, Direction::deg(0));
  CPPUNIT_ASSERT_EQUAL(expected, run.getCrdPosition(&run));

  expected = Position(100, 100, Direction::deg(180));
  CPPUNIT_ASSERT_EQUAL(expected, hand.getCrdPosition(&run));

  expected = Position(0, 100, Direction::deg(270));
  CPPUNIT_ASSERT_EQUAL(expected, urg.getCrdPosition(&run));

  // hand における位置を取得
  expected = Position(100, 100, Direction::deg(180));
  Position3D actual = run.getCrdPosition(&hand);
  CPPUNIT_ASSERT_EQUAL(expected.x, actual.x);
  CPPUNIT_ASSERT_DOUBLES_EQUAL(expected.y, actual.y, 1.0);
  CPPUNIT_ASSERT_EQUAL(expected.zt.to_deg(), actual.zt.to_deg());


  expected = Position(0, 0, Direction::deg(0));
  CPPUNIT_ASSERT_EQUAL(expected, hand.getCrdPosition(&hand));

  expected = Position(100, 0, Direction::deg(90));
  CPPUNIT_ASSERT_EQUAL(expected, urg.getCrdPosition(&hand));

  // urg における位置を取得
  expected = Position(100, 0, Direction::deg(90));
  CPPUNIT_ASSERT_EQUAL(expected, run.getCrdPosition(&urg));

  expected = Position(0, 100, Direction::deg(-90));
  CPPUNIT_ASSERT_EQUAL(expected, hand.getCrdPosition(&urg));

  expected = Position(0, 0, Direction::deg(0));
  CPPUNIT_ASSERT_EQUAL(expected, urg.getCrdPosition(&urg));

  // 位置を更新し、その影響についてテスト
  run.adjustCrdPosition(Position(100, 0, Direction::deg(0)));

  expected = Position(100, 0, Direction::deg(0));
  CPPUNIT_ASSERT_EQUAL(expected, run.getCrdPosition());

  expected = Position(200, 100, Direction::deg(180));
  CPPUNIT_ASSERT_EQUAL(expected, hand.getCrdPosition());

  expected = Position(100, 100, Direction::deg(270));
  CPPUNIT_ASSERT_EQUAL(expected, urg.getCrdPosition());

  hand.adjustCrdPosition(Position(100, 0, Direction::deg(180)), &run);

  expected = Position(100, 0, Direction::deg(0));
  CPPUNIT_ASSERT_EQUAL(expected, run.getCrdPosition());

  expected = Position(200, 0, Direction::deg(180));
  CPPUNIT_ASSERT_EQUAL(expected, hand.getCrdPosition());

  expected = Position(100, 0, Direction::deg(270));
  CPPUNIT_ASSERT_EQUAL(expected, urg.getCrdPosition());
}


class NortifyCoordinateCtrl : public CoordinateCtrl {
  int pre_event;

public:
  enum {
    Create = CoordinateCtrl::Create,
    Remove = CoordinateCtrl::Remove,
    Update = CoordinateCtrl::Update,
  };

  NortifyCoordinateCtrl(void) : pre_event(-1) {
    registerCrdNortifyClient();
  }

  void crdNortify(int event, const CoordinateCtrl* crd)
  {
    static_cast<void>(crd);
    pre_event = event;
  }

  int getPreEvent(void) {
    return pre_event;
  }

  void clearEvent(void) {
    pre_event = -1;
  }
};


void CoordinateCtrlTest::nortifyTest(void) {
  NortifyCoordinateCtrl* crd = new NortifyCoordinateCtrl();
  CPPUNIT_ASSERT(NortifyCoordinateCtrl::Create != crd->getPreEvent());

  // Add の検出テスト
  CoordinateCtrl* test = new CoordinateCtrl();
  CPPUNIT_ASSERT_EQUAL((int)NortifyCoordinateCtrl::Create, crd->getPreEvent());

  // Update の検出テスト
  test->setOwnCrdToCrd(crd);
  CPPUNIT_ASSERT_EQUAL((int)NortifyCoordinateCtrl::Update, crd->getPreEvent());

  crd->clearEvent();
  CPPUNIT_ASSERT((int)NortifyCoordinateCtrl::Update != crd->getPreEvent());

  // Update の検出テスト
  test->updateParentCrdOffset(VXV::Position());
  CPPUNIT_ASSERT_EQUAL((int)NortifyCoordinateCtrl::Update, crd->getPreEvent());

  // Remove の検出テスト
  delete test;
  CPPUNIT_ASSERT_EQUAL((int)NortifyCoordinateCtrl::Remove, crd->getPreEvent());

  // オブジェクトを削除
  delete crd;

  // 削除後のイベントで、エラーが起きないか確認
  test = new CoordinateCtrl();
  delete test;
}


void CoordinateCtrlTest::setOwnCrdToCrdLoopExTest(void) {
  CoordinateCtrl run;
  CoordinateCtrl urg;

  urg.setOwnCrdToCrd(&run);
  run.setOwnCrdToCrd(&urg);
}


void CoordinateCtrlTest::adjustCrdExTest(void) {
  CoordinateCtrl run;
  CoordinateCtrl urg;

  urg.setOwnCrdToCrd(&run);
  run.adjustCrdPosition(VXV::Position(), &urg);
}
