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

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"
#include <string.h>		// memcpy

namespace NIne
{
	/*
		This class doesn't have operator= and shouldn't have it because this behavious is needed.
	*/
	template<typename Type>
	class NDynamicTable
	{
	public:
		NDynamicTable()
			: m_pBuffer(null),
			  m_uSize(0)
		{
		}

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

			m_pBuffer = NNEW Type[uSize];

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

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

			if(src.m_uSize > 0)
			{
				m_pBuffer = NNEW Type[src.m_uSize];
				if(m_pBuffer == null)
				{
					return NRV_OUT_OF_MEMORY;
				}
				m_uSize = src.m_uSize;
				memcpy(m_pBuffer, src.m_pBuffer, m_uSize * sizeof(Type));
			}
			else
			{
				m_pBuffer = null;
			}

			return NRV_SUCCESS;
		}

		void Release()
		{
			NDELETEARRNULL(m_pBuffer);
			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 = NNEW Type[uSize];
			if(pBuffer == null)
			{
				return NRV_OUT_OF_MEMORY;
			}
			memcpy(pBuffer, m_pBuffer, m_uSize * sizeof(Type));
			delete [] 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;
	};

	// Funkcje pomocnicze
	template<typename TYPE>
	void NSwap(TYPE& srcA, TYPE& srcB)
	{
		TYPE temp;
		temp = srcA;
		srcA = srcB;
		srcB = srcA;
	}
}