/* Autor: Tomasz Kogut, Grupa dziekańska: 5ISI.
 * Ostatnia aktualizacja: 11.12.2008
 */

/* Opis */
/*---------------------------------------------*/
/* Poniższy listing ma za zadanie pokazać użycie funkcji bibliotecznych:
 * bool is_sorted( iterator start, iterator end );
 * bool is_sorted( iterator start, iterator end, Ordering cmp )
 * których zadaniem jest stwierdzenie czy dany zbiór jest posortowany.
 */


/* Biblioteka zawierająca naszą funkcje. Bez niej nie możemy używać
 * funkcji is_sorted.
 */
#include <ext/algorithm>
#include <iostream>
#include <vector>
#include <iterator>
#include <cmath>

using namespace std;



/* Klasa reprezentująca zwykły kwadrat.
 * Ma jedną składową - długość boku, która jest całkowita.
 * Klasa stworzona do zaprezentowania przykładowego użycia.
 */
class Kwadrat {
	public:
		//Konstruktor
		Kwadrat(int bok) : _bok(bok) {};

		//Przeciążony operator porównywania. Jest wykorzystywany
		//przez funkcję is_sorted do ustalania relacji.
		bool operator<(const Kwadrat& inny) const {
			return (this->_bok < inny._bok);
		};

		//Pobieranie danej. W przykładzie nie używana.
		int zwroc_bok() const {return _bok;};

	private:
		//długość boku kwadratu.
		int _bok;
};

/*	Funkcja sprawdza czy pierwszy argument leży bliżej zera
 *	niż argument drugi na osi współrzędnych.
 *	Funkcja dostarczana opcjonalnie dla is_sorted. Używana
 *	zamiast operatora '<'. Argumenty powinny być typu
 *	jak elementy porównywane przez is_sorted.
 *	Wynik zwracany powinien być konwertowalny do typu bool.
 */
bool czy_blizej_zera(int a, int b) {
	a = abs(a);
	b = abs(b);
	return (a < b ? true : false);
}


int main(int argc, char* argv[]) {

	//Deklaracja danych na których będziemy operować.
	int tab1[] = {1,2,3,4,5,6,7,8};
	int tab2[] = {1,-2,-3,4,5,-6,7,-8};
	//Ilość elementów w tablicy
	const int N1 = sizeof(tab1) / sizeof(int);
	const int N2 = sizeof(tab2) / sizeof(int);

	//Wektor kwadratów o bokach z tab1
	std::vector<Kwadrat> wektor;
	for(int i = 0; i < N1; ++i)
		wektor.push_back(Kwadrat(tab1[i]));

	//Iteratory do pokazania jednego z możliwych wywołań funkcji is_sorted
	vector<Kwadrat>::iterator pierwszy = wektor.begin();
	vector<Kwadrat>::iterator ostatni = wektor.end();

	//Sposób wywołania funkcji:
	//Dla tablicy
	cout << __gnu_cxx::is_sorted(tab1, tab1+N1) << endl;
	//Dla kontenerów udostępniających iteratory
	cout << __gnu_cxx::is_sorted(pierwszy,ostatni) << endl;
	//Gdy chcemy zastosować własne kryteria porównywania, podajemy wskaźnik na funkcje jako 3 parametr
	cout << __gnu_cxx::is_sorted(tab2,tab2+N2, &czy_blizej_zera) << endl;

	/* Program po uruchomieniu powinien wypisać trzy 1 pod sobą oznaczające, że is_sorted stwierdziła
	 * posortowanie danych we wszystkich trzech przypadkach
	 */



	/*
	 * Funkcji można użyć do znajdowania minimum i maximum. Przykład poniżej.
	 */

	//Pomocnicza tablica do której kopiujemy dane
	//Zapamiętamy największą do tej pory znalezioną liczbę i będziemy ją porównywać z kolejnymi
	//danymi z tablicy.
	int max[2] = {0, tab1[0]};
	for(int z=1; z < N1; ++z) {
		max[0] = tab1[z];
		if(!__gnu_cxx::is_sorted(max, max+2))
			//znaleźliśmy większą liczbę, należy ją zapamiętać.
			max[1] = max[0];
	}

	/*
	 * W max[1] znajduje się maksimum. Podobnie można znajdować minimum na wektorze liczb.
	 * Taki sposób wyszukiwania ekstremów jest przydatny gdy dostarczamy swoją funkcję porównującą,
	 * według jakiegoś niestandardowego wzorca.
	 */

}
