#ifndef Object_hpp
#define Object_hpp

#include <graphics/Graphics.hpp>
#include <graphics/Mesh.hpp>

class Object {
  friend class Logic;
  static std::vector<Object*> objects;
  bool active = false;
  bool inAir = true;
  Vector speed;
  Matrix matrix;
public:
  typedef double Time;
protected:
  const unsigned long getCollisions(
    std::vector<Object*>& collisions,
    const Vector& position
  ) const;
  virtual Object& onCollision(Object* object = nullptr);
  virtual const Vector* getAcceleration() const;
  virtual Object& simulatePosition(
    Vector& position,
    const Time dt
  );
  virtual Object& simulate(const Time dt);
  virtual const Object& render() const = 0;
public:
  Object();
  virtual ~Object();
  virtual const double getRxz() const = 0;
  virtual const double getRy() const;
  virtual const bool isStatic() const;
  virtual const bool isTransparent() const;
  const bool isInAir() const;
  const bool isActive() const;
  const bool isFront(const Vector& position) const;
  const bool isLeft(const Vector& position) const;
  const double getDistance(const Vector& position) const;
  virtual Object& setActive(const bool active = true);
  const Vector& getPosition() const;
  Object& setPosition(const Vector& position);
  Object& setPosition(
    const double x,
    const double y,
    const double z
  );
  Object& setPosition(
    const double x,
    const double z
  );
  const Vector& getDirection() const;
  Object& setDirection(const Vector& direction);
  Object& lookAt(const Vector& position);
  const Vector& getSpeed() const;
  virtual Object& setSpeed(const Vector& v);
  Object& setSpeed(
    const double x = 0,
    const double z = 0
  );
  virtual std::ostream& operator >> (std::ostream& os) const;
};

std::ostream& operator << (
  std::ostream& os,
  const Object& o
);

class MeshObject : public Object {
  const Object& render() const override;
  mutable double rXZ = 0;
protected:
  mutable double rY = 0;
  Matrix matrix;
  virtual const bool useMatrix() const;
  virtual const Mesh& getMesh() const = 0;
  virtual const MeshObject& renderMesh() const;
  std::ostream& operator >> (std::ostream& os) const override;
public:
  const double getRxz() const override;
  const double getRy() const override;
};

#endif
