/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include "RxArray2DBase.h"

#include "Rx.Interop.Runtime30/IMemory2D.h"
#include "Rx.Core.Math/RxMatrix.h"

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Rx
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rx
{
	/**
	\addtogroup RxCore_Tools
	**/
	/// @{

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 	2D Array base class.
	/// </summary>
	///
	/// <typeparam name="TValue"> VALUE. </typeparam>
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	template<class TValue>
	class CRxArray2DBase : public Interop::Runtime30::IMemory2D
	{
	public:

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Default constructor. Creates an empty 2D array.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		CRxArray2DBase()
		{
			New(0, 0);
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Constructor. Creates a 2D array with the given number of rows and columns.
		/// </summary>
		///
		/// <param name="nRows">    The number of rows. </param>
		/// <param name="nColumns"> The number of columns. </param>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		CRxArray2DBase(size_t nRows, size_t nColumns)
		{
			New(nRows, nColumns);
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Copy constructor. Creates a copy of the given 2D array.
		/// </summary>
		///
		/// <param name="xArray"> The array to copy. </param>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		CRxArray2DBase(const CRxArray2DBase& xArray)
		{
			*this = xArray;
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Destructor.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		virtual ~CRxArray2DBase()
		{
		}

	public:

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Assignment operator.
		/// </summary>
		///
		/// <param name="xArray"> The array to copy. </param>
		///
		/// <returns> This array. </returns>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		CRxArray2DBase& operator=(const CRxArray2DBase& xArray)
		{
			m_xMatrix.CopyFrom(&xArray);
			return *this;
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Get the element at the position described by the given row and column.
		/// </summary>
		///
		/// <param name="nRow">    The row. </param>
		/// <param name="nColumn"> The column. </param>
		///
		/// <returns> The element. </returns>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		TValue& operator()(size_t nRow, size_t nColumn)
		{
			if ((nRow >= m_xMatrix.GetRowCount()) || (nColumn >= m_xMatrix.GetColCount()))
			{
				RX_THROW(CRxException, "Array index out of bounds");
			}

			return m_xMatrix(nRow, nColumn);
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Get the element at the position described by the given row and column.
		/// </summary>
		///
		/// <param name="nRow">    The row. </param>
		/// <param name="nColumn"> The column. </param>
		///
		/// <returns> The element. </returns>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		const TValue& operator()(size_t nRow, size_t nColumn) const
		{
			if ((nRow >= m_xMatrix.GetRowCount()) || (nColumn >= m_xMatrix.GetColCount()))
			{
				RX_THROW(CRxException, "Array index out of bounds");
			}

			return m_xMatrix(nRow, nColumn);
		}

	public:

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Gets the pointer to the internal data.
		/// </summary>
		///
		/// <returns> The pointer. </returns>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		TValue* GetDataPtr()
		{
			return m_xMatrix.GetDataPtr();
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Gets the pointer to the internal data.
		/// </summary>
		///
		/// <returns> The pointer. </returns>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		const TValue* GetDataPtr() const
		{
			return m_xMatrix.GetDataPtr();
		}

	public:

		/************************************************************************/
		/* Rx::Interop::Runtime30::IMemory2D                                    */
		/************************************************************************/

		virtual void New(size_t nRows, size_t nCols)
		{
			m_xMatrix.New(nRows, nCols);
		}

		virtual void Resize(size_t nRows, size_t nCols)
		{
			m_xMatrix.Resize(nRows, nCols);
		}

		virtual void Delete()
		{
			m_xMatrix.Delete();
		}

		virtual void Reset()
		{
			m_xMatrix.Reset();
		}

		virtual void CopyFrom(const IMemory2DAccess* pMemory)
		{
			return m_xMatrix.CopyFrom(pMemory);
		}

		virtual size_t GetElementSize() const
		{
			return m_xMatrix.GetElementSize();
		}

		virtual void GetSize(size_t& nRows, size_t& nCols) const
		{
			m_xMatrix.GetSize(nRows, nCols);
		}

		virtual bool IsValid() const
		{
			return m_xMatrix.IsValid();
		}

		virtual void* GetPointer()
		{
			return GetDataPtr();
		}

		virtual const void* GetPointer() const
		{
			return GetDataPtr();
		}

	protected:

		/// <summary> The internal matrix. </summary>
		CRxMatrix<TValue> m_xMatrix;
	};

	/// @}
}
