#include "Tree.hpp"
#include <logic/Fire.hpp>

const bool Tree::isStatic() const {
  return true;
}

const bool Tree::useMatrix() const {
  return timer > 0 || MeshObject::useMatrix();
}

Object& Tree::onCollision(Object* object) {
  if (
    object != nullptr && !useMatrix() && dynamic_cast<const Fire*>(object)
  ) {
    timer = 1;
  }
  return MeshObject::onCollision(object);
}

Object& Tree::simulate(const Time dt) {
  if (
    isActive() && timer > 0
  ) {
    timer = (std::max)(
      timer - dt,
      0.0
    );
    const double k = sin(Math::PImul2 * timer * 3) * timer / 7;
    static Matrix m;
    matrix.setTranslate(
      0,
      - getRy()
    ) *= m.setYRotation(Math::PI * k);
    matrix *= m.setXRotation(Math::PIdiv4 * k);
    matrix *= m.setTranslate(
      0,
      getRy()
    );
  }
  return MeshObject::simulate(dt);
}

Object& Tree::setActive(const bool active) {
  if (active) {
    timer = 0;
  }
  return MeshObject::setActive(active);
}

Play::Tree::Mesh::Leaf::Leaf() {
  static const Vector v = Vector(
    0,
    2.125,
    0.5
  );
  rotateZ(- Math::PIdiv4).setColor(
    Color(Color::Cyan) /= 4
  ).setVector(
    Vector(
      v.x,
      1.5,
      v.y
    ),
    v
  ).setColor(
    v,
    Color::Cyan
  );
}

Play::Tree::Mesh::Mesh(const unsigned int size) {
  rotateZ(- Math::PIdiv2).setColor(Color::Cyan);
  ::Mesh* axis = size == 1 ? nullptr : clone();
  {
    Leaf* mesh = new Leaf();
    *this += (*mesh += Vector::Y).rotateY(Math::PIdiv4);
    delete mesh;
  }
  (
    round(10) *= 0.5
  ).rotateZ(Math::PIdiv4);
  {
    ::Mesh* mesh = clone();
    mesh->rotateY(Math::PI);
    *this += *mesh;
    delete mesh;
  }
  {
    ::Mesh* mesh = clone();
    for (
      unsigned int i = 1;
      i < size;
      i++
    ) {
      (*this += *axis) += (*mesh += Vector::Y).rotateY(Math::PIdiv2);
      *axis += Vector::Y;
    }
    delete mesh;
  }
  delete axis;
  for (
    unsigned int i = 0;
    i < size;
    i++
  ) {
    setColor(
      0,
      i,
      0,
      Color::White
    );
  }
  randomizeXZ(0.125).centralize().setLight();
}

const Mesh& Play::Tree::getMesh() const {
  return mesh;
}

Play::Tree::Tree(const unsigned int size) : mesh(size) {
}
