#pragma once

#include "scene/Entity.h"

#include "types/Matrix44.h"

namespace common {
class ObjectLink;
}

namespace scene {

class Scene;

namespace actor {

class Cache;

CLASS( Actor, Entity )

	typedef float coord_t;

	// normal type must be always followed by it's INSTANCED_ type, see Instanced.cpp
	enum type_t {
		TYPE_SPRITE,
		TYPE_INSTANCED_SPRITE,
		TYPE_MESH,
		TYPE_INSTANCED_MESH,
		TYPE_TEXT,
		TYPE_SOUND,
		TYPE_CACHE,
	};

	Actor( const type_t type, const std::string& name );
	virtual ~Actor();
	const type_t GetType() const {
		return m_type;
	}

	common::ObjectLink* m_graphics_object = NULL;

	virtual types::Matrix44& GetWorldMatrix();

	virtual void UpdateWorldMatrix();
	virtual void UpdateMatrix() override;

	virtual const types::Vec3 NormalizePosition( const types::Vec3& position ) const;

	void SetScene( Scene* scene );
	Scene* GetScene();

	typedef std::pair< types::Vec3, types::Vec3 > area_limits_t;
	void SetAreaLimits( const area_limits_t limits );
	void RemoveAreaLimits();
	const area_limits_t& GetAreaLimits() const;

	typedef uint32_t render_flag_t;
	static constexpr render_flag_t RF_NONE = 0;
	static constexpr render_flag_t RF_USE_TINT = 1 << 0;
	static constexpr render_flag_t RF_IGNORE_LIGHTING = 1 << 1;
	static constexpr render_flag_t RF_IGNORE_CAMERA = 1 << 2;
	static constexpr render_flag_t RF_IGNORE_DEPTH = 1 << 3;
	static constexpr render_flag_t RF_USE_AREA_LIMITS = 1 << 4;
	static constexpr render_flag_t RF_USE_2D_POSITION = 1 << 5;
	static constexpr render_flag_t RF_SPRITES_DEPTH = 1 << 6;

	void SetRenderFlags( const render_flag_t render_flags );
	const render_flag_t GetRenderFlags() const;

	void SetCacheParent( Cache* const cache_parent );
	const Cache* const GetCacheParent() const;

	void Show() override;
	void Hide() override;

	virtual const types::Buffer Serialize() const override;
	virtual void Unserialize( types::Buffer buf ) override;

protected:
	const type_t m_type;

	struct {
		types::Matrix44 world;
	} m_actor_matrices;

	bool m_need_world_matrix_update = true;

	Scene* m_scene = NULL;

	render_flag_t m_render_flags = RF_NONE;
	area_limits_t m_area_limits = {};

	void UpdateCache();

private:
	Cache* m_cache_parent = nullptr;

};

}
}
