/*
 * Autor: Piotr Miecielica J1ISI
 * Temat: Biblioteka STL opis algorytmów : remove_copy, remove_copy_if
 *
 * Aby korzystać z algorytmów STL należy załączyć(#include) bibliotekę algorithm.
 *
 *
 * Deklaracja funkcji replace_copy:
 *
 * template < class InputIterator, class OutputIterator, class T >
 * 	OutputIterator replace_copy ( 	InputIterator first, InputIterator last,
 * 									OutputIterator result, const T& old_value,
 * 									const T& new_value );
 *
 *
 * Deklaracja funkcji replace_copy_if:
 *
 * template < class InputIterator, class OutputIterator, class Predicate, class T >
 * 	OutputIterator replace_copy_if ( 	InputIterator first, InputIterator last,
 * 										OutputIterator result, Predicate pred,
 * 										const T& new_value );
 *
 *
 * Działanie algorytmów replace_copy i replace_copy_if polega na kopiowaniu wartości
 * kontenera (zakres określony przez first i last) do miejsca, którego początek wskazuje iterator result.
 * Jeśli aktualnie kopiowany element ma wartość równą old_value (w przypadku replace_copy) bądź
 * spełniającą predykat pred (w przypadku replace_copy_if), to w zamian jest kopiowana wartość
 * wyznaczona przez new_value.
 *
 * Wynik zwracany: iterator wskazujący na element za ostatnim skopiowanym elementem zbioru do którego
 * kopiowaliśmy
 *
 *
 * Warto zauważyć, że algorytm może zmodyfikować zbiór który przegląda(wszystko zależy od tego na co
 * wskazuje result). Kontener do którego kopiujemy musi mieć zakres sięgający co najmniej
 * result + (last-first).
 */

#include<iostream>
#include<algorithm>
#include<functional> //dla unary_function
#include<list>
#include<vector>

using namespace std;



//Pomocnicza funkcja szablonowa do wyswietlania elementów z zakresu [beg,end)

template <class InputIterator>
	void print(const InputIterator& beg, const InputIterator& end)
{
	if(beg == end) {
 		 cout << "Brak elementow!" << endl;
 		 return;
 	}
	int i = 0;
	InputIterator it=beg;
	while(it != end) {
       cout << "[" << ++i << "]:= " << *it << endl;
	   ++it;
	}
}

/*
 * Bardzo prosty funktor - zwraca wartość true, jeśli porównywane string są takie same
 */
template <typename T>
 struct MyPredicate : public unary_function<T,bool>{
	private:
		T value;

	public:
		MyPredicate(const T& v): value(v){}
		bool operator()(const T& v)const {
			if( value==v ) return true;
			return false;
		}
};

/*
 * funkcja sprawdza czy podany string ma mniej niż 14 znaków i czy kończy się na literę 'e'
 * zwraca true przy spełnienieniu powyższych warunków lub false w przeciwnym wypadku
 */
bool check(const string& v)
{
	if(v.size()<14 && *--v.end()=='e') return true;
	return false;
}



int main(int argc, char** argv){

	typedef bool (*MyFunPred)(const std::string&);


	list<string> difficult_words; //lista angielskich słów, w pisowni których łatwo się pomylić

	//przykładowe wypełnienie listy
	difficult_words.push_back("victoriously"); difficult_words.push_back("non-flammable");
	difficult_words.push_back("acquaintance"); difficult_words.push_back("irresponsible");
	difficult_words.push_back("entertainingly"); difficult_words.push_back("enthronement");
	//celowo wprowadzone błędne nazwy:
	difficult_words.push_back("adress"); difficult_words.push_back("leav");


	//Wyświetlanie zawartości listy trudnych słów
	list<string>::const_iterator beg=difficult_words.begin();
	list<string>::const_iterator end=difficult_words.end();
	list<string>::iterator result=difficult_words.begin();
	cout<<"Poczatkowa zawartosc listy trudnych wyrazow:"<<endl;
	print(beg, end);


	/*
	 * UŻYCIE:
	 * Po powyższym wyświetleniu wyłapujemy, że lista zawiera błędnie napisane wyrazy.
	 * korekty można dokonać w bardzo prosty sposób.
	 *
	 * użyta funkcja: replace_copy
	 */

	cout<<endl<<"W wyniku: replace_copy(beg, end, result, string(\"leav\"), string(\"leaf\") )"
		<<" zawartosc listy trudnych wyrazow:"<<endl;
	replace_copy( beg, end, result, string("leav"), string("leaf") );
	print(beg, end); //drukujemy zawartosc listy

	/*
	 * UŻYCIE:
	 * Ten sam problem co wyżej, rozwiązany z wykorzystaniem predykatu.
	 *
	 * użyta funkcja: replace_copy_if
	 */
	cout<<endl<<"W wyniku: replace_copy_if(beg, end, result, MyPredicate<string>(\"adress\"), \"address\")"
		<<" zawartosc listy trudnych wyrazow:"<<endl;
	replace_copy_if(beg, end, result, MyPredicate<string>( string("adress") ) , string("address"));
	print(beg, end); //drukujemy zawartosc listy

	/*
	 * UŻYCIE:
	 *
	 * Inny przykład użycia replace_copy_if, który nie jest możliwy do osiągnięcia za pomocą replace_copy
	 * Za predykat posłuży funkcja check.
	 * Tym razem jednak zbiór, który przegląda replace_copy_if nie będzie modyfikowany - wynik działania
	 * zostanie zapisany do innego kontenera. Kontener ten będzie innego typu.
	 *
	 * użyta funkcja: relace_copy_if
	 */


	vector<string> vec( difficult_words.size() ); //utworzenie nowego kontenera o odpowiednim rozmiarze
	vector<string>::iterator result_vec = vec.begin();

	cout<<endl<<"W wyniku: replace_copy_if(beg, end, result_vec, (MyFunPred)check, \"possessive vector entry\")"
		<<" zawartosc nowo utworzonego wektora trudnych wyrazow:"<<endl;
	replace_copy_if(beg, end, result_vec, (MyFunPred)check, string("possessive vector entry"));
	print(result_vec, vec.end()); //drukujemy zawartosc wektora
	return 0;
}

