#pragma once
#include "model_class.h"
#include <WICTextureLoader.h>
#include <SimpleMath.h>

#include "d_3d_class.h"

enum class ObjectType
{
	Sphere,
	Cube,
	Unknown
};

enum class ShaderType
{
	CEL_SHADING,
	LIGHTING,
	NORMAL_MAPPING,
	SPECULAR_MAPPING,
	REFLECTION,
	REFRACTION,
	TEXTURE,
	SKYBOX,
	SUNLIGHT,
	ALPHA_MAPPING
};

class object
{
public:
	object(application_class& app);
	object();
	~object();

	object(const object&) = delete;
	object& operator=(const object&) = delete;

	bool Initialize(
		ID3D11Device* device,
		ID3D11DeviceContext* deviceContext,
		char* modelFilename,
		TextureContainer& texturesContainer
		);

	void SetScaleMatrix(XMMATRIX scaleMatrix);
	void SetRotateMatrix(XMMATRIX rotateMatrix);
	void SetTranslateMatrix(XMMATRIX translateMatrix);
	void SetSRMatrix(XMMATRIX srMatrix);
	void SetWorldMatrix(XMMATRIX worldMatrix);

	void SetPosition(XMVECTOR position);
	void SetRotation(XMVECTOR rotation);
	void SetScale(XMVECTOR scale);

	XMMATRIX GetScaleMatrix() const;
	XMMATRIX GetRotateMatrix() const;
	XMMATRIX GetTranslateMatrix() const;
	XMMATRIX GetSRMatrix() const;
	XMMATRIX GetWorldMatrix() const;

	XMVECTOR GetPosition();
	XMVECTOR GetRotation();
	XMVECTOR GetScale();

	void SetVelocity(XMVECTOR);
	void AddVelocity(float deltaTime);
	XMVECTOR GetVelocity() const;
	void SetAcceleration(XMVECTOR);
	XMVECTOR GetAcceleration() const;
	void SetMass(float);
	float GetMass() const;
	void SetGrounded(bool);
	bool IsGrounded() const;
	bool IsPhysicsEnabled() const;
	void SetPhysicsEnabled(bool state);
	void SetVisible (bool state) { m_isVisible = state; }
	bool IsVisible() const { return m_isVisible; }

	void UpdateWorldMatrix();
	void UpdateSRMatrix();
	void UpdateScaleMatrix();
	void UpdateRotateMatrix();
	void UpdateTranslateMatrix();

	void UpdatePosition(float deltaTime);

	void Update();

	std::string GetName();
	void SetName(std::string name);
	int SetId(int id);
	int GetId() const;
	void SetType(ObjectType type);
	ObjectType GetType() const { return m_type; };

	ShaderType GetActiveShader() const { return m_activeShader; };
	void SetActiveShader(ShaderType activeShader) { m_activeShader = activeShader; };

	float GetBoundingRadius() const;
	void SetBoundingRadius(float radius) { m_boundingRadius = radius; }

	void SetModelPath(std::wstring& path) { m_modelPath = path; }
	std::wstring& GetModelPath() { return m_modelPath; }

	ShaderType StringToShaderType(const std::string& shaderType);
	std::string ShaderTypeToString(ShaderType shaderType);

	ObjectType StringToObjectType(const std::string& objectType);
	std::string ObjectTypeToString(ObjectType objectType);

	void LaunchObject();
	bool LoadTexturesFromPath(std::vector<std::wstring>& texturePaths, TextureContainer& texturesContainer,d_3d_class* m_Direct3D);
	bool SetupInstancing(ID3D11Device* device, const std::vector<XMMATRIX>& instanceTransforms);
	void EnableInstancing(bool enabled);
	void SetInstanceCount(int count);
	bool IsInstancingEnabled() const;
	int GetInstanceCount() const;
	ID3D11Buffer* GetInstanceBuffer() const;
	void SetAlpha(float alpha) { m_alpha = alpha; }
	float GetAlpha() const { return m_alpha; }
	void SetInitialStretch(float initialStretch) { m_initialStretch = initialStretch; }
	float GetInitialStretch() const { return m_initialStretch; }
	void SetSpringConstant(float springConstant) { m_springConstant = springConstant; }
	float GetSpringConstant() const { return m_springConstant; }

	bool IsGravityEnabled() const { return m_gravityEnabled; }
	void SetGravityEnabled(bool state) { m_gravityEnabled = state; }

	std::shared_ptr<model_class> get_model() const { return m_model_; }
	void SetModel(std::shared_ptr<model_class> model) { m_model_ = model; }

public :
	bool m_demoSpinning = false;
	XMVECTOR m_previousPosition;
	XMVECTOR m_velocity;
	int m_id;
	bool m_gravityEnabled = true;

private:

	application_class& m_Application;
	
	XMMATRIX m_scaleMatrix;
	XMMATRIX m_rotateMatrix;
	XMMATRIX m_translateMatrix;
	XMMATRIX m_srMatrix;
	XMMATRIX m_worldMatrix;

	XMVECTOR m_acceleration;
	float m_mass;
	bool m_isGrounded;
	bool m_isPhysicsEnabled;
	bool m_isVisible;

	std::string m_name;
	ObjectType m_type = ObjectType::Unknown;
	ShaderType m_activeShader = ShaderType::LIGHTING;

	float m_boundingRadius;
	std::wstring m_modelPath;
	TextureContainer m_texturesContainer;
	float m_alpha = 0.0f;
	float m_initialStretch = 0.0f;
	float m_springConstant = 10.0f;

	std::shared_ptr<model_class> m_model_;
	
};
