
#pragma once
#ifndef Cgarray_H
#define  Cgarray_H

#define GARRAY_INCREMENT 100
#include "b_file.h"
//array generico---------------------------------
/*
Clase para manejar arrays genericos de cualquier tipo de clase o estructura
*/
template <typename T>
class Cgarray
{
public:
	//variables----------------------------------------------------------------------------------
	int m;         //cache del array
	int n;         //numero de elementos en array
	int increment; //valor a incrementar en la cache
	T* ptr;   //array de elementos
	//**************************************************************
	//constructores-------------------------------------------------------------------------------
	//**************************************************************
	Cgarray()
	{
		m=0;
		ptr=NULL;
		n=0;
		increment=GARRAY_INCREMENT;
	};
	//**************************************************************
	Cgarray(int cache)//constructor poniendo en memoria posiciones
	{
		m=cache;
		ptr=(T*)malloc(sizeof(T)*m);
		if (ptr)
			memset(ptr,0,m * sizeof(T));
		else
			m=0;
		n=0;
		increment=GARRAY_INCREMENT;
	};
	//**************************************************************
	~Cgarray() 
	{	
		if (ptr)
			free(ptr);
	};
	//**************************************************************
	//funciones-----------------------------------------------------------------------------------
	//**************************************************************
	 inline  T& operator[](int i)//da el elemento i-esimo por referencia 
	{ 
		return ptr[i];
	};
	//**************************************************************
	 inline T* get(int i)//da el elemento i-esimo
	{ 
		return &ptr[i] ;
	};
	//**************************************************************
	inline void remove(int ini, int nelem = 1)
	{
		if(ini<0)
			ini =0;
		if(ini>=n || nelem<1)
			return;
		int fin = ini+nelem;
		if(fin>=n)
		{
			n =ini;
			return;
		}

		memmove(&ptr[ini], &ptr[fin], (n-fin)*sizeof(T));
		n-=(fin-ini);
	};
	//**************************************************************
	inline BOOL operator+(T &e )//aņade nuevo elemento
	{ 
		T*pp;
		if (m<n+1)
		{
			m+=increment;
			if (ptr)
				pp=(T*)realloc(ptr,sizeof(T)*m);
			else
				pp=(T*)malloc(sizeof(T)*m);
			if (!pp)
			{
				m-=increment;
				return FALSE;
			}
			ptr=pp;
			memset(&ptr[m-increment],0,increment);
		}
		ptr[n]=e;
		n++;
		return TRUE ;
	};
	//**************************************************************
	inline BOOL operator+=(int mas )//aņade memoria para mas elementos
	{ 
		T*pp;
		int inc=n+mas-m;
		if (inc>0)
		{
			if (inc<increment)
				inc=increment;
			m+=inc;
			if (ptr)
				pp=(T*)realloc(ptr,sizeof(T)*m);
			else
				pp=(T*)malloc(sizeof(T)*m);
			if (!pp)
			{
				m-=inc;
				return FALSE;
			}
			ptr=pp;
			memset(&ptr[m-inc],0,inc);
		}
		return TRUE ;
	};
	//**************************************************************
	inline BOOL ajusta_mem()
	{
		if(n == m)
			return TRUE;
		int oldm = m;
		m = n;
		if(m<=0 && ptr)
		{
			free(ptr);
			ptr = NULL;
			m =0;
			return true;
		}

		T* pp=(T*)realloc(ptr,sizeof(T)*m);
		if(!pp)
		{
			m = oldm;
			return FALSE;
		}
		ptr = pp;
		return TRUE;
	}
	//**************************************************************
	inline BOOL operator+(Cgarray<T> &e) //aņade una lista entera
	{ 
		int inc=n+e.n-m;
		T*pp;
		if (inc>0)
		{
			if (inc<increment)
				inc=increment;
			m+=inc;
			if (ptr)
				pp=(T*)realloc(ptr,sizeof(T)*m);
			else
				pp=(T*)malloc(sizeof(T)*m);
			if (!pp)
			{
				m-=inc;
				return FALSE;
			}
			ptr=pp;
			memset(&ptr[m-inc],0,inc);
		}
		memcpy(&ptr[n],e.ptr,e.n*sizeof(T));
		n+=e.n;
		return TRUE ;
	};
	//**************************************************************
	/*inline BOOL add(Cgarray<T> *e) //aņade una lista entera
	{ 
		int inc=n+e->n-m;
		T*pp;
		if (inc>0)
		{
			if (inc<increment)
				inc=increment;
			m+=inc;
			if (ptr)
				pp=(T*)realloc(ptr,sizeof(T)*m);
			else
				pp=(T*)malloc(sizeof(T)*m);
			if (!pp)
			{
				m-=inc;
				return FALSE;
			}
			ptr=pp;
			memset(&ptr[m-inc],0,inc);
		}
		memcpy(&ptr[n],e->ptr,e.n*sizeof(T));
		n+=e->n;
		return TRUE ;
	};*/
		//**************************************************************
	inline BOOL insert(int pos, T *e, int ne = 1) //inserta apartir de la posicion pos los elementos de la lista, desplaza los existentes para alante
	{
		if (pos >= n)
			return add(e, ne);
		int inc = n + ne - m;
		if (!e || ne <= 0)
			return FALSE;
		if (!operator+=(inc))
			return false;
		//adelanta los elementos necesarios
		for (int i = n - 1; i >= pos; i--)
			ptr[i + ne] = ptr[i];

		memcpy(&ptr[pos], e, ne * sizeof(T));
		n += ne;
		return TRUE;
	};
	//**************************************************************
	inline BOOL add(T *e, int ne) //aņade una lista de elementos
	{ 
		int inc=n+ne-m;
		if (!e || ne<=0)
			return FALSE;
		T*pp;
		if (inc>0)
		{
			if (inc<increment)
				inc=increment;
			m+=inc;
			if (ptr)
				pp=(T*)realloc(ptr,sizeof(T)*m);
			else
				pp=(T*)malloc(sizeof(T)*m);
			if (!pp)
			{
				m-=inc;
				return FALSE;
			}
			ptr=pp;
			memset(&ptr[m-inc],0,inc);
		}
		memcpy(&ptr[n],e,ne*sizeof(T));
		n+=ne;
		return TRUE ;
	};
	//**************************************************************
	inline void borra()//libera la memoria del array 
	{
		if (ptr)
			free(ptr);
		ptr=NULL;
		m=n=0;
	}
	//**************************************************************
	inline BOOL graba(Cb_file *file)//graba en archivo el array
	{
		if(!file->escribe(&n,sizeof(n)))
			return FALSE;
		if(!file->escribe(ptr,n*sizeof(T)))
			return FALSE;
		return TRUE;
	}
	//**************************************************************
	inline BOOL leer(Cb_file *file)//lee de archivo el array
	{
		int nn;
		if(!file->lee(&nn,sizeof(n)))
			return FALSE;
		if( nn<=0 || !((*this)+=nn))
			return FALSE;
		if(!file->lee(&ptr[n],nn*sizeof(T)))
			return FALSE;
		n+=nn;
		return TRUE;
	}
	//**************************************************************
};
#endif