#ifndef LP_ARRAY_H
#define LP_ARRAY_H

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

template <class MY_TYPE, int MY_STATIC_SIZE>
class LP_Array
{
public:
  LP_Array()
  : data(staticData)
  , size(0)
  , capacity(MY_STATIC_SIZE)
  {
    LP_ASSERT(MY_STATIC_SIZE != 0);
  }

  ~LP_Array()
  {
    if(data != staticData)
      delete data;
  }

  MY_TYPE& operator[](const int index) const
  {
    LP_ASSERT(index >= 0);
    LP_ASSERT(index < size);
    return data[index];
  }

  void Add(const MY_TYPE& a)
  {
    if(size == capacity)
    {
      capacity *= 2;
      MY_TYPE* tmp = new MY_TYPE[capacity];
      memcpy(tmp, data, sizeof(MY_TYPE) * size);
      if(data != staticData)
        delete data;
      data = tmp;
    }
    data[size] = a;
    size++;
  }

  void Remove(const MY_TYPE& a)
  {
    for(int i = 0; i < size; i++)
    {
      if(data[i] == a)
      {
        RemoveAt(i);
        return;
      }
    }
  }

  void RemoveConserveOrder(const MY_TYPE& a)
  {
    for(int i = 0; i < size; i++)
    {
      if(data[i] == a)
      {
        RemoveAtConserveOrder(i);
        return;
      }
    }
  }

  void RemoveAt(const int index)
  {
    LP_ASSERT(index >= 0);
    LP_ASSERT(index < size);

    size--;
    data[index] = data[size];
  }

  void RemoveAtConserveOrder(const int index)
  {
    LP_ASSERT(index >= 0);
    LP_ASSERT(index < size);

    if(index != (size - 1))
      memmove(data + index, data + index + 1, (size - index) * sizeof(MY_TYPE));
    size--;
  }

  MY_TYPE& GetLast()
  {
    LP_ASSERT(size >= 0);
    return data[size - 1];
  }

  MY_TYPE& RemoveLast()
  {
    LP_ASSERT(size >= 0);
    size--;
    return data[size];
  }

  int Count() const
  {
    return size;
  }

  void Randomize(int numIterations)
  {
    if(size < 2)
    {
      return;
    }
    for(int i = 0; i < numIterations; i++)
    {
      int i1 = random() % size;
      int i2 = random() % size;
      MY_TYPE tmp = data[i1];
      data[i1] = data[i2];
      data[i2] = tmp;
    }
  }

private:
  MY_TYPE staticData[MY_STATIC_SIZE];
  MY_TYPE *data;
  int size;
  int capacity;
};

#endif
