#pragma once

#ifndef __gx_graphicsdevice_h__
	#define __gx_graphicsdevice_h__

#include "foundation.h"
#include "material.h"
#include "indexbuffer.h"
#include "vertexbuffer.h"
#include "graphicsresource.h"
#include "contentmanager.h"

namespace Gx
{
	class Game;
	class Surface;
	class Context;
	class Mesh;
	class Model;
	class BasicEffect;

	struct GX_API GraphicsDeviceDesc
	{
		GraphicsDeviceDesc();

		bool isFullScreen;
		GxU32 surfaceWidth;
		GxU32 surfaceHeight;
		GxU32 majorVersion;
		GxU32 minorVersion;

		GxI32	colorBits;
		GxI32	alphaBits;
		GxI32	depthBits;
		GxI32	stencilBits;
		GxI32	aliasingSamples;
	};

	class GX_API GraphicsDevice
	{
		friend class Game;
	public:
		GraphicsDevice(Game* game);
		virtual ~GraphicsDevice();

		void prepareDevice(const GraphicsDeviceDesc& desc);

		IndexBuffer* createIndexBuffer(IndexElementType::Enum indexElementType, GLuint indexCount, GLenum usage);
		VertexBuffer* createVertexBuffer(const VertexDeclaration& declaration, GLuint vertexCount, GLenum usage);

		void clear(const PxVec4& color);
		BasicEffect* getBasicEffect();
		void renderModel(BasicEffect* effect, Model* model);
		void renderMesh(BasicEffect* effect, Mesh* mesh, const Material& material = Material::Default);

		template<typename T>
		VertexDeclaration createVertexDeclaration() {
			return VertexDeclaration(createVector(T::VertexAttributes), sizeof(T));
		}

		template<typename T>
		VertexBuffer* createVertexBuffer(GLuint vertexCount, GLenum usage) {
			return this->createVertexBuffer(this->createVertexDeclaration<T>(), vertexCount, usage);
		}

		void addResource(GraphicsResource* resource);

		ContentManager& getContentManager() {
			return *m_content.get();
		}

	private:
		GraphicsDevice(const GraphicsDevice&);
		GraphicsDevice& operator=(const GraphicsDevice&);

		void flush();

		Game* m_game;
		BasicEffect* m_basicEffect;
		GraphicsDeviceDesc m_desc;
		std::unique_ptr<Surface> m_surface;
		std::unique_ptr<Context> m_context;
		std::unique_ptr<ContentManager> m_content;
		std::vector<std::unique_ptr<GraphicsResource>> m_resources;
	};
}

#endif /* __gx_graphicsdevice_h__ */