#ifndef _GEO_OBJ_PHYSICS_H_
#define _GEO_OBJ_PHYSICS_H_

#include "Geo_Obj_Textured.h"
#include "Collider.h"
#include <list>

class CollisionManager;

namespace Geo
{
	class GeoObjPhysics : public GeoObjTextured
	{
	protected:
		friend class CollisionManager; // I think it might be a bit faster than using all of the getter/setter functions

		Collider mCollider;
		glm::vec3 mVelocity;
		float mMass;
		bool mIsKinematic;	// If true, it's position/movement wont be affected by collisions (like a wall)
		bool mUseGravity;	// If false, gravity won't be applied to it

		bool mIsSleeping;	// If true, it's collision won't be checked with other sleeping objects, and won't have gravity applied to it
		bool mAbleToSleep;	// If this is true, it will wait until it collides with a sleeping object or one with infinite(0) mass before sleeping
		int mSleepFrameCounter; // Goes up while its motion is less than a sleep epsilon. Sleeps at certain number of consecutive sleeping frames
		float mRWAMotion;	// The Recently Weighted Average for this objects motion. Is used to see if it hasn't moved much and needs to sleep
		std::list<GeoObjPhysics*> mObjectsSleepingOnThis; // Objects that fell asleep on this object. When this wakes up, it wakes up all others.

		void CheckMinMaxVelocity();
		void Move(); // Simply moves it by its velocity
		void CheckIfSleeping();
		void Sleep();
		void WakeUp(); // Collision Manager will call this

	public:
		GeoObjPhysics(Data::GeoData& aModelData, Textures::Data::TextureData& aTextureData);
		void Update();
		float GetInverseMass();

		// These are overriden to apply transforms to the collider as well
		virtual void SetPosition(glm::vec3 aPos);
		virtual void Translate(glm::vec3 aVec);
		virtual void SetScale(glm::vec3 aScale);
		virtual void Scale(glm::vec3 aScale);
		virtual void UpdateBindRender();

		virtual void ColliderHit() {} // Is run if it is in a collision

		void SetVelocity(glm::vec3 aVel) { mVelocity = aVel; }
		void AddVelocity(glm::vec3 aVel) { mVelocity += aVel; }
		void SetMass(float aMass) { mMass = aMass; }
		void AddMass(float aVal) { mMass += aVal; }
		void SetIsKinematic(bool aState) { mIsKinematic = aState; }
		bool IsKinematic() const { return mIsKinematic; }
		void SetUseGravity(bool aState) { mUseGravity = aState; }
		bool IsUseGravity() const { return mUseGravity; }
		Collider& GetCollider() { return mCollider; }
		glm::vec3& GetVelocity() { return mVelocity; }
	};
}

#endif // Close _GEO_OBJ_PHYSICS_H_