//    This program is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program; if not, write to the Free Software
//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//

#include "carray.h"

//constructs new object - 0 size
CArray::CArray()
{
	m_iAllocatedBlocks = 0;
	m_iArrayItems = 0;
	m_pFirstBlock = NULL;
}

//destructor calls destroy
CArray::~CArray()
{
	Destroy();
}

//destructs all sub array blocks
void CArray::Destroy()
{
	if ( m_iAllocatedBlocks )
	{
		SubArray* pCurr = m_pFirstBlock;
		SubArray* pNext;

		while ( pCurr )
		{
			pNext = pCurr->pNext;
			delete pCurr;
			pCurr = pNext;
		}
	}

	m_iAllocatedBlocks = 0;
	m_iArrayItems = 0;
	m_pFirstBlock = NULL;
}

//deletes last item
BOOL CArray::DeleteLast()
{
	m_iArrayItems--;
	return TRUE;
}

//gets value from array
void* CArray::GetAt( int iItem )
{
	if ( ( iItem + 1 ) > m_iArrayItems )
		return NULL;

	int iBlockNeeded = iItem / CARRAY_SUB_SIZE;

	int iBlockCurr = 0;

	SubArray* pCurr = m_pFirstBlock;

	while( iBlockCurr < iBlockNeeded )
	{
		pCurr = pCurr->pNext;
		iBlockCurr++;

		if ( !pCurr )
			return NULL;
	}

	return pCurr->array[ iItem % CARRAY_SUB_SIZE ];
}

//sets array's value - must exist before
BOOL CArray::SetAt( int iItem, void* pPtr )
{
	if ( ( iItem + 1 ) > m_iArrayItems )
		return FALSE;

	int iBlockNeeded = iItem / CARRAY_SUB_SIZE;

	int iBlockCurr = 0;

	SubArray* pCurr = m_pFirstBlock;

	while( iBlockCurr < iBlockNeeded )
	{
		pCurr = pCurr->pNext;
		iBlockCurr++;
		if ( !pCurr )
			return FALSE;
	}

	pCurr->array[ iItem % CARRAY_SUB_SIZE ] = pPtr;
	return TRUE;
}

//adds array's value
BOOL CArray::Add( void* pPtr )
{
	if ( ((( m_iArrayItems ) / CARRAY_SUB_SIZE ) + 1 ) > m_iAllocatedBlocks )
	{
		//if we need new block, we try to add them
		if ( !AddNewBlock() )
			return FALSE;
	}

	m_iArrayItems++;

	if ( !SetAt( m_iArrayItems - 1, pPtr ) )
	{
		m_iArrayItems--;
		return FALSE;
	}

	return TRUE;

}

//adds new sub array block
BOOL CArray::AddNewBlock()
{
	SubArray* pCurr = m_pFirstBlock;
	SubArray* pNext = m_pFirstBlock;

	//find end
	while ( pNext )
	{
		pCurr = pNext;
		pNext = pCurr->pNext;
	}

	if ( !( pNext = new SubArray ) )
		return FALSE;

	memset( pNext, 0, sizeof( SubArray) );

	if ( !m_pFirstBlock )
		m_pFirstBlock = pNext;
	else
		pCurr->pNext = pNext;

	m_iAllocatedBlocks++;

	return TRUE;
}