#include "Tank.hpp"

TankMesh::Head::Head(
  const Color& color,
  const double size
) : CylinderMesh(
  8,
  1,
  true,
  true
), position(
  0,
  0.175 * size,
  0.05 * size
) {
  rotateY(Math::PI / 8).scale(
    0.25,
    0.2,
    0.2
  );
  for (
    Vertices::iterator i = vertices.begin();
    i < vertices.end();
    i++
  ) {
    Vector* v = *i;
    if (v->y > 0.1) {
      v->scale(
        Vector(
          0.75,
          1,
          0.75
        )
      );
    }
  }
  setColor(
    Color(color) /= 1.5
  ).setLight(
    Color(color) /= 2
  ) *= size;
}

TankMesh::Gun::Gun(
  const Color& color,
  const double size
) : CylinderMesh(
  12,
  1,
  true
), position(
  0,
  0.1 * size,
  0.125 * size
) {
  static const Vector v = Vector(
    0,
    0,
    0.25
  );
  rotateX(- Math::PIdiv2).scale(
    0.05,
    0.05,
    0.25
  ).setVector(
    v,
    Vector(v) *= 2
  ).setVector(
    Vector(v) *= 2,
    v
  ).setColor(
    Color(color) /= 1.5
  ).setLight(
    Color(color) /= 2
  );
  center = getVertex(v);
  *this *= size;
}

TankMesh::Gun& TankMesh::Gun::setCenterColor(const Color& color) {
  *center = color;
  return *this;
}

TankMesh::TankMesh(
  const Color& color,
  const double size
) : BoxMesh(
  false,
  3,
  3,
  2
), size(size), wheels(
  0.15 * size,
  0.6 * size,
  5.0 / 3
), head(
  color,
  size
), gun(
  color,
  size
) {
  rotateX(Math::PIdiv2).centralize().round(10);
  for (
    unsigned int i = 0;
    i < 4;
    i++
  ) {
    const double d = static_cast<double>(i) - 1.5;
    setVector(
      -1.5, -1, d,
      -0.5, 0, d
    ).setVector(
      1.5, -1, d,
      0.5, 0, d
    ).setVector(
      d, 1, -1.5,
      d, 0, -1.5
    ).setVector(
      d, 1, 1.5,
      d, 0, 1.5
    );
    if (
      abs(d) < 1
    ) {
      setVector(
        d, -1, 1.5,
        d, 0, 1.5
      ).setVector(
        d, -1, -1.5,
        d, 0, -1.5
      ).setVector(
        -1.5, 1, d,
        -1, 1, d
      ).setVector(
        1.5, 1, d,
        1, 1, d
      );
    }
  }
  mergeVertices(0.25);
  for (
    Vertices::iterator i = vertices.begin();
    i < vertices.end();
    i++
  ) {
    Vector* v = *i;
    if (v->z > 0 && v->y > 0.25) {
      v->scale(
        Vector(
          1,
          1,
          1.75
        )
      );
    }
  }
  scale(
    0.3,
    0.15,
    0.3
  ).setColor(
    Color(color) /= 2
  ).setLight() *= size;
}

const bool TankEnemy::heroIsVisible() const {
  if (
    TankEnemyParent::heroIsVisible()
    &&
    hero.xzDistance < Graphics::get()->R / 2
  ) {
    if (
      const Hero* hero = FirstPerson::Logic::get()->getHero()
    ) {
      return this->hero.yDistance < (
        hero->getRy() + getRy()
      ) * 2;
    }
  }
  return false;
}

const bool TankEnemy::getIsLeftTurn() const {
  return heroIsVisible() ? hero.isLeft : TankEnemyParent::getIsLeftTurn();
}

Object& TankEnemy::setAction(const EnemyAction action) {
  if (action == Fire) {
    setAction(Stop);
  }
  return TankEnemyParent::setAction(action);
}

Object& TankEnemy::simulate(
  const EnemyAction action,
  const Object::Time dt
) {
  switch (action) {
    case Walk:
      if (
        heroIsVisible()
      ) {
        return setAction(Turn);
      } else {
        matrix.setYRotation(
          sin(
            Logic::get()->getTimer() * Math::PI * 3 / 2
          ) * Math::PI / 0x40
        );
      }
      break;
    case Turn:
      if (
        heroIsAtGunPoint()
      ) {
        return setAction(Fire);
      }
      break;
    case Fire:
      if (
        heroIsAtGunPoint()
      ) {
        fire();
      } else {
        return setAction(Turn);
      }
  }
  return TankEnemyParent::simulate(
    action,
    dt
  );
}
