/*********************************************************************

Name:		Raytracer
Author:		Kamil Szatkowski "Netrix" (C)
Website:	http://www.netrix.org.pl/
License:	GNU GPL

*********************************************************************/
#pragma once

#include "nBase.hpp"
#include "nAssert.hpp"
#include "nErrors.hpp"

namespace NIne
{
	template<typename Type>
	class NAlignedDynamicTable
	{
	public:
		NAlignedDynamicTable()
			: m_pBuffer(null),
			  m_uSize(0)
		{
		}

		NRESULT Create(NSize_t uSize, NSize_t uAlignment)
		{
			NAssert(m_pBuffer == null, "Buffer already allocated");
			NAssert(uSize > 0, "uSize is too small");

			NAlignedAlloc(&m_pBuffer, uSize * sizeof(Type), uAlignment);

			if(m_pBuffer == null)
			{
				return NRV_OUT_OF_MEMORY;
			}
			m_uAlignment = uAlignment;
			m_uSize = uSize;
			return NRV_SUCCESS;
		}

		NRESULT Create(const NAlignedDynamicTable<Type>& src)
		{
			NAssert(m_pBuffer == null, "Buffer already allocated");

			if(src.m_uSize > 0)
			{
				NAlignedAlloc(&m_pBuffer, src.m_uSize * sizeof(Type), src.m_uAlignment);

				if(m_pBuffer == null)
				{
					return NRV_OUT_OF_MEMORY;
				}
				m_uAlignment = src.m_uAlignment;
				m_uSize = src.m_uSize;
				memcpy(m_pBuffer, src.m_pBuffer, m_uSize * sizeof(Type));
			}
			else
			{
				m_pBuffer = null;
			}

			return NRV_SUCCESS;
		}

		void Release()
		{
			if(m_pBuffer != null)
			{
				NAlignedFree(m_pBuffer);
				m_pBuffer = null;
			}

			m_uSize = 0;
		}

		const Type* GetBuffer() const
		{
			return m_pBuffer;
		}

		Type* GetBuffer()
		{
			return m_pBuffer;
		}

		const Type& operator[](NSize_t uIndex) const
		{
			NAssert(m_pBuffer != null, "DynamicTable not initializated");
			NAssert(uIndex < m_uSize, "Index out of bounds");

			return m_pBuffer[uIndex];
		}

		Type& operator[](NSize_t uIndex)
		{
			NAssert(m_pBuffer != null, "DynamicTable not initializated");
			NAssert(uIndex < m_uSize, "Index out of bounds");

			return m_pBuffer[uIndex];
		}

		NSize_t GetSize() const
		{
			return m_uSize;
		}

		NRESULT Resize(NSize_t uSize)
		{
			NAssert(m_pBuffer != null, "Buffer not allocated");
			NAssert(uSize > 0, "uSize is too small");
			
			if(uSize == m_uSize)
			{
				return NRV_SUCCESS;
			}

			Type* pBuffer = null;
			NAlignedAlloc(&pBuffer, uSize * sizeof(Type), m_uAlignment);

			if(pBuffer == null)
			{
				return NRV_OUT_OF_MEMORY;
			}
			memcpy(pBuffer, m_pBuffer, m_uSize * sizeof(Type));
			NAlignedFree(m_pBuffer);
			m_pBuffer = pBuffer;
			m_uSize = uSize;
			return NRV_SUCCESS;
		}

		operator bool() const
		{
			return m_pBuffer != null;
		}

	private:
		Type* m_pBuffer;
		NSize_t m_uSize;
		NSize_t m_uAlignment;
	};
}