#include "garray.h"
//array generico ordenado---------------------------------
#ifndef CARRAY_ORD_DEF


#define CARRAY_ORD_DEF
#define  GARRAY_O_MODO_EXACTO 0 //devuelve el elemento exacto si esta en la lista si no null
#define  GARRAY_O_MODO_MENOR  1//devuelve el elemento menor mas cercano de la lista(si existe)
#define  GARRAY_O_MODO_MAYOR  2//devuelve el elemento mayor mas cercano de la lista (si existe)

template<typename T1, typename T2>
class Cgarray_ord
{
public:
	Cgarray<int> ind;
	Cgarray<T1>	dat;
public:
	int (*f_ord)(T1* e1,T1*e2);//resultado de comparar e1 con e2
	int (*fcomp)( T2 * t, T1*e);//resultado de comparar t con e
	int modo;
	//**************************************************************
	Cgarray_ord(){f_ord=NULL; fcomp=NULL;modo=GARRAY_O_MODO_EXACTO;};
	~Cgarray_ord(){};
	//**************************************************************
	inline  T1& operator[](int i)//da el elemento i-esimo por referencia 
	{ 
		return dat[ind[i]];
	};
	//**************************************************************
	inline  int getix(T2*index)//da el indice elemento  segun indexado
	{ 
		int f=dat.n-1, i=0 ,a=-1,res;
		if((fcomp==NULL))
			return -1;
		if(dat.n<=0)
			return -1;
		//dicotomica-------------------
		while(f-i>1)
		{
			a=(f-i)/2+i;
			res=fcomp(index,get(a));
			if (res<0)
				f=a;
			else if (res>0)
				i=a;
			else
				return a;
		}
		res=fcomp( index,get(f));
		if(res==0)
			return f;
		else if (res<0 && modo==GARRAY_O_MODO_MAYOR)
			return f;
		res=fcomp( index, get(i));
		if(res==0)
			return i;
		else if(res>0 && modo==GARRAY_O_MODO_MENOR)
			return i;
	
		else if (res<0 && modo==GARRAY_O_MODO_MAYOR)
			return f;
		
		return -1;
	};
	//**************************************************************
	 inline T1* getx(T2*index)//da el elemento  segun indexado
	{ 
		int i=getix(index);
		if(i<0)
			return NULL;
		return dat.get(ind[i]) ;
	};
	//**************************************************************
	 inline T1* get(int i)//da el elemento i-esimo
	{ 
		return dat.get(ind[i]) ;
	};
	//**************************************************************
	inline BOOL operator+(T1 &e )//aņade nuevo elemento
	{ 
		int f=dat.n-1, i=0 ,a=-1,res;
		if((f_ord==NULL) || !(ind+=1) || !(dat+e) )
			return FALSE;
		//dicotomica-------------------
		while(f-i>1)
		{
			a=(f-i)/2+i;
			res=f_ord(&e,get(a));
			if (res<0)
				f=a;
			else if (res>0)
				i=a;
			else
				f=i=a;
		}
		if (f<0)
		{
			a=0;
		}
		else if (i!=f || a<0)
		{
			res=f_ord(&e,get(f));
			if (res>0)
				a=f+1;
			else if (0>f_ord(&e,get(i)))
			{
				a=i;
			}
			else
				a=f;
		}
		
		if ((a)<ind.n)
			memcpy(&ind.ptr[a+1],&ind.ptr[a], sizeof(int)*(ind.n-a));
		ind.n++;
		ind[a]=dat.n-1;
		return TRUE ;
	};
	//**************************************************************
	inline BOOL operator+=(int mas )//aņade memoria para mas elementos
	{ 
		return ((dat+=mas) && (ind+=mas));
	};
	//**************************************************************
	inline BOOL operator-=(int i )//borra el elemento iesimo
	{ 
		int idi=ind[i];
		for(idi=0; idi<ind.n; idi++)
		{
			if(ind[idi]>ind[0])
				ind[idi]--;
		}
		if(i<(ind.n-1))
			memcpy(ind.get(i), ind.get(i+1), sizeof(int)*(ind.n-i-1));
		if((idi+1)<dat.n)
			memcpy(dat.get(idi),dat.get(idi+1), sizeof(T1)*(dat.n-idi-1));

		dat.n--;
		ind.n--;
		return TRUE;
	};
	//**************************************************************
	inline BOOL operator-(T2*index )//borra el elemento correspondiente a el index
	{ 
		int idi= getix(index);
		return (idi>=0)&& operator-=(idi);
	};
	//**************************************************************
	inline void borra()//libera la memoria del array 
	{
		ind.borra();
		dat.borra();
	}
	//**************************************************************
};
#endif