#pragma once

#include "volumeshop.h"
#include "Exception.h"

#define VBOBUFFERS   2

class VertexBufferedObject
{
public:

	enum RenderStyle {FILLED= GL_TRIANGLES, LINES = GL_LINES, POINTS = GL_POINTS};

	VertexBufferedObject(std::vector<GLfloat>& aVertices,std::vector<GLuint>& aIndices) : m_indicesCount(aIndices.size()) , m_renderStyle(RenderStyle::FILLED)
	{
		if (!GLEW_ARB_vertex_buffer_object)
		{
			std::cerr << "GL_ARB_vertex_buffer_object is not supported by your hardware or driver." << std::endl;
			throw Exception("GL_ARB_vertex_buffer_object is not supported by your hardware or driver.");
		}
		create(aVertices,aIndices,m_GLvboBufferIds);
	};

	virtual ~VertexBufferedObject()
	{
		cleanup();
	};

	void create(const std::vector<GLfloat>& aVertices, const std::vector<GLuint>& aIndices,	GLuint* aVBOIds)
	{

		const GLenum glError = glGetError();
		if (glError != GL_NO_ERROR)
		{
			std::cout << " gl error" <<  std::endl;
		}   while(glError != GL_NO_ERROR);


		glGenBuffers(VBOBUFFERS, aVBOIds);

		int vboArrayBufferId =m_GLvboBufferIds[0];
		int vboIndexBufferId =m_GLvboBufferIds[1];

		for (int i=0;i<VBOBUFFERS; i++)
			if (!glIsBuffer(aVBOIds[i]) )
				std::cout << " glGenBuffers error" <<  std::endl;

		// Bind the buffer object, OpenGL initially creates it empty.
		glBindBuffer(GL_ARRAY_BUFFER, vboArrayBufferId );
		glBufferData( GL_ARRAY_BUFFER, aVertices.size()*sizeof(GLfloat), &(aVertices.front()),GL_STATIC_DRAW ); // Tell OpenGL to copy data from the 'vertices' pointer into   the buffer object.

		glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIndexBufferId );
		glBufferData( GL_ELEMENT_ARRAY_BUFFER, aIndices.size()*sizeof(GLuint), &(aIndices.front()), GL_STATIC_DRAW );

		glBindBuffer( GL_ARRAY_BUFFER, 0 );
		glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );

		if (glGetError() != GL_NO_ERROR)
			std::cout << " glGenBuffers error" <<  std::endl;
	}

	void draw()
	{
		int vboArrayBufferId =m_GLvboBufferIds[0];
		int vboIndexBufferId =m_GLvboBufferIds[1];

		long indices = m_indicesCount;

		glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
		glEnableClientState( GL_VERTEX_ARRAY );
		glBindBuffer( GL_ARRAY_BUFFER, vboArrayBufferId );
		glVertexPointer( 3, GL_FLOAT, 0, bufferObjectPtr( 0 ) );

		glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIndexBufferId );
		glDrawRangeElements(m_renderStyle, 0, indices,indices,	 GL_UNSIGNED_INT, bufferObjectPtr( 0) );

		glBindBuffer( GL_ARRAY_BUFFER, 0 );
		glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
		glPopClientAttrib();

		if (glGetError() != GL_NO_ERROR)
			std::cout << " glGenBuffers error" <<  std::endl;
	}

	void cleanup()
	{
		glDeleteBuffers(VBOBUFFERS ,m_GLvboBufferIds);
		std::cout << "Cleanup called for vbobuffers " << m_GLvboBufferIds[0] << " and " << m_GLvboBufferIds[1] << std::endl;
	}

	inline GLvoid* bufferObjectPtr( unsigned int idx )
	{
		return (GLvoid*)( ((char*)NULL) + idx );
	}

	void setRenderStyle(RenderStyle aRenderStyle)
	{
		m_renderStyle=aRenderStyle;
	}

private:
	GLuint m_GLvboBufferIds[VBOBUFFERS];
	long m_indicesCount;
	RenderStyle m_renderStyle;
};