#include "malgorithms.h"

//Predicado (función que devuelve bool entre dos iteradores) Devuelve cierto si el elemento está entre los dos iteradores
template <class ITERATOR, class TYPE>
bool in(ITERATOR i_begin, ITERATOR i_end, TYPE value)
{
	while ( (i_begin != i_end) && (value != *i_begin) ) ++i_begin;
	return (i_begin != i_end);
}

//Estructuras PREDICATES que derivan de mbinary_function y munary_function
template <class TYPE>
struct pequal : public mbinary_function<TYPE, TYPE, bool>
{
	bool operator() (const TYPE& arg1, const TYPE& arg2) const { return arg1 == arg2;}
};

template <class TYPE>
struct pnotequal : public mbinary_function<TYPE, TYPE, bool>
{
	bool operator() (const TYPE& arg1, const TYPE& arg2) const { return arg1 != arg2;}
};

template <class TYPE>
struct pless : public mbinary_function<TYPE, TYPE, bool>
{
	bool operator() (const TYPE& arg1, const TYPE& arg2) const { return arg1 < arg2;}
};

template <class TYPE>
struct pless_equal : public mbinary_function<TYPE, TYPE, bool>
{
	bool operator() (const TYPE& arg1, const TYPE& arg2) const { return arg1 <= arg2;}
};

template <class TYPE>
struct pgreater : public mbinary_function<TYPE, TYPE, bool>
{
	bool operator() (const TYPE& arg1, const TYPE& arg2) const { return arg1 > arg2;}
};

template <class TYPE>
struct pgreater_equal : public mbinary_function<TYPE, TYPE, bool>
{
	bool operator() (const TYPE& arg1, const TYPE& arg2) const { return arg1 >= arg2;}
};

template <class TYPE>
struct plogical_not : public munary_function<TYPE, bool>
{
	bool operator() (const TYPE& arg) const { return !arg;}
};

template <class TYPE>
struct ppair : public munary_function<TYPE, bool>
{
	bool operator() (const TYPE& arg) const { return ((arg%2)==0);}
};

template <class TYPE>
struct pdiv : public binary_function<TYPE, TYPE, bool>
{
	bool operator() (const TYPE& arg1, const TYPE& arg2) const { return ((arg1%arg2)==0);}
};


//Funciones "m " de recorrido y de iteración
template <class ITER_FOR, class FUNCT_UN>
FUNCT_UN mfor_each(ITER_FOR begin, ITER_FOR end, FUNCT_UN f)
{
	while (begin != end) f(*begin++);
	return f;
}

template <class ITER_FOR1, class ITER_FOR2, class FUNCT_BI>
FUNCT_BI mfor_each(ITER_FOR1 begin1, ITER_FOR1 end1, ITER_FOR2 begin2, FUNCT_BI f)
{
	while (begin1 != end1) f(*begin1++, *begin2++);
	return f;
}

template <class ITER_FOR, class ITER_OUT, class FUNCT_UN>
ITER_OUT mtransform(ITER_FOR begin, ITER_FOR end, ITER_OUT o, FUNCT_UN f)
{
	while (begin != end) *o++ = f(*begin++);
	return o;
}

template <class ITER_FOR1, class ITER_FOR2, class ITER_OUT, class FUNCT_BI>
ITER_OUT mtransform(ITER_FOR1 begin1, ITER_FOR1 end1, ITER_FOR2 begin2, ITER_OUT o, FUNCT_BI f)
{
	while (begin1 != end1) *o++ = f(*begin1++, *begin2++);
	return o;
}

template <class ITER_FOR, class ITER_OUT, class FUNCT_BI, class PRED>
ITER_OUT mtransform_if(ITER_FOR begin, ITER_FOR end, ITER_OUT o, FUNCT_BI f, PRED p)
{
	for (;begin != end; ++begin) if(p(*begin)) *o++ = f(*begin++);
	return o;
}

template <class ITER_IN>
ITER_IN mfind(ITER_IN i_begin, ITER_IN i_end, typename ITER_IN::CONST_REF_VALUE value)
{
	while ( (i_begin!=i_end) && (*i_begin != value) ) ++i_begin;
	return i_begin;
}

//La condición de búsqueda la establece si cumple "true" el predicado
template <class ITER_IN, class PREDICATE>
ITER_IN mfind_if (ITER_IN i_begin, ITER_IN i_end, PREDICATE pred)
{
	while ( ( i_begin != i_end )  && ( !pred(*i_begin) ) ) ++i_begin;
	return i_begin;
}

template <class ITER_IN, class ITER_OUT>
ITER_OUT mcopy(ITER_IN i_begin, ITER_IN i_end, ITER_OUT o)
{
	while(i_begin != i_end) *o++ = *i_begin++;
	return o;
}

template <class ITER_OUT, class TYPE>
ITER_OUT mcopy(unsigned int n, TYPE value, ITER_OUT o)
{
	unsigned int cont;
	for(cont = 0; cont < n ; ++cont) *o++ = value;
	return o;
}

//¿alguien sabe construir un predicado para esta función?
//Debe responder cierto o falso si es la posición es la adecuada dentro del vector
template <class ITER, class PRED>
void msort(ITER i_begin, ITER i_end, PRED s)
{
	ITER i = i_begin;
	
	for (++i; i =! i_end; ++i);
	{
		ITER r_end = mfind_if(i_begin, i, setarg1(s, *i));
		if (r_end != i)
		{
			typename MITERATOR_TRAITS<ITER>::ELEMENT value = *i;
			ITER r_from = i;
			ITER r_to   = i;
			do *r_to-- = *--r_from; while (r_from != r_end);
			*r_end = value;
		}
	}

}
//Dejo los algoritmos más usuales para ordenar una estructura
/* 
Debe ser de este tipo, algo como esto pero que ordene.

template <class TYPE>
struct ppair : public munary_function<TYPE, bool>
{
	bool operator() (const TYPE& arg) const 
	{ 
		return ((arg%2)==0);
	}
};

} */		
