/*
 * gen_dynarray.c: The dynamic array implementation
 *
 * See the README file for copyright information and how to reach the author.
 *
 * $Id: gen_dynarray.c,v 1.3 2005/12/22 10:42:20 cm Exp $
 */

#include <string.h>
#include "gen_dynarray.h"

// --- cDynamicArray -----------------------------------------------------------

template <typename ItemType>
cDynamicArray<ItemType>::cDynamicArray(bool ownership) :
  m_ownership(ownership), m_itemBufferSize(0), m_numOfItems(0), mp_items(NULL) {
}

template <typename ItemType>
cDynamicArray<ItemType>::~cDynamicArray() {
  if (NULL != mp_items) {
    if (m_ownership) {
      for (int i = 0; i < m_numOfItems; i++)
        delete mp_items[i];
    }

    delete[] mp_items;
  }
}

/*template <typename ItemType>
ItemType cDynamicArray<ItemType>::operator[](int index) const {
  if (NULL != mp_items && 0 <= index && index < m_numOfItems)
    return mp_items[index];

  return NULL;
}*/

template <typename ItemType>
bool cDynamicArray<ItemType>::Resize(void) {
  ItemType *ptr = NULL;

  ptr = new ItemType[m_itemBufferSize + 32];

  if (NULL != ptr) {
    memset(ptr, 0x00, (m_itemBufferSize + 32) * sizeof(ItemType));
    if (NULL != mp_items);
      memcpy(ptr, mp_items, m_itemBufferSize * sizeof(ItemType));

    delete[] mp_items;
    mp_items = ptr;
    m_itemBufferSize += 32;
  } else
    return false;

  return true;
}

template <typename ItemType>
ItemType cDynamicArray<ItemType>::Item(int index) const {
  if (NULL != mp_items && 0 <= index && index < m_numOfItems)
    return mp_items[index];

  return NULL;
}

// takes ownership of item
template <typename ItemType>
ItemType cDynamicArray<ItemType>::Add(ItemType item) {
  ItemType temp = NULL;

  if (NULL != item) {
    if (m_numOfItems == m_itemBufferSize)
      Resize();

    if (m_numOfItems != m_itemBufferSize) {
      mp_items[m_numOfItems] = item;
      m_numOfItems++;

      temp = item;
    }
  }

  return temp;
}

// returns -1 on error
template <typename ItemType>
int cDynamicArray<ItemType>::Delete(int index) {
  if (NULL != mp_items && 0 <= index && index < m_numOfItems) {
    if (m_ownership)
      delete mp_items[index];
    m_numOfItems--;

    if (index < m_numOfItems)
      memmove(&mp_items[index], &mp_items[index+1], (m_numOfItems - index) * sizeof(ItemType));

    mp_items[m_numOfItems] = NULL;
  } else
    return -1;

  return m_numOfItems;
}

// returns -1 when cannot move item, otherwise new position
template <typename ItemType>
int cDynamicArray<ItemType>::Move(int dest, int src) {
  ItemType temp = NULL;

  if (NULL != mp_items &&  dest != src &&
      0 <= dest && dest < m_numOfItems && 0 <= src && src < m_numOfItems) {
    temp = mp_items[src];

    if (dest < src)
      memmove(&mp_items[dest+1], &mp_items[dest], (src - dest) * sizeof(ItemType));
    else if (dest > src)
      memmove(&mp_items[src], &mp_items[src+1], (dest - src) * sizeof(ItemType));

    mp_items[dest] = temp;
  } else
    return -1;

  return dest;
}

// returns index position when item is found; otherwise -1
template <typename ItemType>
int cDynamicArray<ItemType>::Contains(ItemType item) const {
  for (int i = 0; i < m_numOfItems; i++)
    if (mp_items[i] == item)
      return i;

  return -1;
}

template <typename ItemType>
bool cDynamicArray<ItemType>::Clear(void) {
  if (NULL != mp_items && 0 < m_numOfItems) {
    if (m_ownership) {
      for (int i = 0; i < m_numOfItems; i++)
        delete mp_items[i];
    }

    memset(mp_items, 0x00, m_itemBufferSize * sizeof(ItemType));
    m_numOfItems = 0;
  }

  return true;
}

template <typename ItemType>
void cDynamicArray<ItemType>::Pack(void) {
  if (NULL != mp_items) {
    if (m_numOfItems < m_itemBufferSize && 0 != m_numOfItems) {
      ItemType *temp = new ItemType[m_numOfItems];

      if (NULL != temp) {
        memcpy(temp, mp_items, m_numOfItems * sizeof(ItemType));
        delete[] mp_items;
        mp_items = temp;
        m_itemBufferSize = m_numOfItems;
      }
    }
  }
}
