// Paweł Pasznik H1ISI //
//---------------------//

/*
	Algorytm find_first_of zaimplementowany jest jako dwie przeciążone funkcje:

	template <class InputIterator, class ForwardIterator>
		InputIterator find_first_of(InputIterator first1, InputIterator last1,
                            ForwardIterator first2, ForwardIterator last2);

	template <class InputIterator, class ForwardIterator, class BinaryPredicate>
		InputIterator find_first_of(InputIterator first1, InputIterator last1,
                            ForwardIterator first2, ForwardIterator last2,
                            BinaryPredicate comp);

	InputIterator - to taki iterator z którego może być wyłuskany obiekt, powinien też pozwalać wskazywać na następny iterator w sekwencji.

	ForwardIterator - to taki iterator, który służy do przeglądania liniowej sekwencji wartości, aczkolwiek nie potrafi działać wstecz jak sama nazwa wskazuje. Doskonale nadaje się do wieloprzejściowego przeglądania danych.

	Funkcje te różnią się tym, że w pierwszej domyślnym predykatem jest po prostu operator== (musi istnieć operator== dla argumentów typu
	wyłuskanych InputIterator i ForwardIterator), a w drugim można podać własny warunek za pomocą predykatu lub funkcji.
	
	find_first_of operuje na dwóch kontenerach, przeglądajac je za pomocą iteratorów. Dla rozróżnienia nazwe je konternerem wzorcowym i kontenerem przesukiwanym.

	find_first_of(przeszukiwanyKontener.begin(), przeszukiwanyKontener.end(), kontener_wzorcowy.begin(), kontener_wzorcowy.end());

	Działa podobnie jak zwykły find z tą różnicą, że wyszukuje w zakresie wyznaczonym iteratorami kontenera wzorcowego pierwszego wystąpienia wartości
	w kontenerze przeszukiwanym (również w jego części lub całości wyznaczonej poprzez iteratory. 

	Aby skorzystać z algorytmu find_first_of należy włączyć plik nagłówkowy: algorithm

*/

#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <list>
#include <iostream>

/*
	Przykładowym zastosowaniem find_first_of jest wyszukiwanie białych znaków w tekście, np. aby zliczyć słowa.
*/

int countWords(const char* str)
{
	const char* whitespace = "\t\n \0";	//znaki traktowane jako białe
	const int numberOfWhitespaces = 4;	//nie moge się posłużyć strlen ponieważ zależy mi, żeby znak \0 również się zawierał
	unsigned words = 0;
	
	while (*str != '\0')			//każdy ciąg znakowy w stylu C kończy się znakiem \0, jest on też wyszukiwany w zbiorze
	{					//białych znaków, aby uwzględnić ostatnie słowo w obiczeniach
		++str; 				//przeskakuje do badania kolejnego znaku (dopiero tutaj aby nie wyjść poza zakres ciągu znakowego.
		++words;			//jeśli nadal jestem w pętli doliczam znalezienie słowa

		//zmieniam początek przeszukiwanego ciągu napisowego na pierwszy znalezioniony biały znak
		//(ciąg przesukiwany: cały znak od ostatniego znalezionego białego znaku lub początku słowa; ciąg wzorcowy: białe znaki)
		str = std::find_first_of(str, str + strlen(str), whitespace, whitespace + numberOfWhitespaces);	
	}
return words;
}

/*
	Warto zauważyć, że kontener std::string zawiera metodę find_first_of działającą trochę inaczej.
	(nie można jej mylić z wyżej przedstawionym algorytmem, nawet nie potrzebuje pliku nagłówkowego: algorithm)

	size_t find_first_of ( const string& str, size_t pos = 0 ) const;
	size_t find_first_of ( const char* s, size_t pos, size_t n ) const;
	size_t find_first_of ( const char* s, size_t pos = 0 ) const;
	size_t find_first_of ( char c, size_t pos = 0 ) const;
	
	Nie operuje na iteratorach. Zwraca pozycje w napisie. Ciągiem przeszukiwanym jest tutaj obiekt na rzecz, którego metoda jest wywoływana,
	a ciągiem wzorcowym podany jako argument ciąg znaków (ew. znak lub std::string)

	Argumenty:
	s / str / c - wyszukiwane znaki
	pos - pozycja w obiekcie stringa na rzecz którego metoda jest wywoływana, od której ma być zaczęte wyszukiwanie.
	n - ilość znaków w s, które mają być brane pod uwagę podczas wyszukiwania.
*/

size_t firstColor(const std::string str, size_t intro)	//intro: ile znaków na od początku std::string ma pominąć.
{
	char colors[4] = "RGB";				//ciąg znakowy wyszukiwanych znaków (w przykładzie kolory)
	return str.find_first_of(colors, intro);
}


/*
	Bardziej wyrafinowanym przykładem użycia algorytmu find_first_of jest zastosowanie go z innym typem kontenera niż napisowy,
	z własnym predykatem lub przeciążonym operatorem operator==
	Poniżej zaprezentuje przykład z przeciążonym operatorem operator==.
*/

class Owoc
{
	std::string nazwa_;
	unsigned nr;
public:
	Owoc(std::string nazwa) : nazwa_(nazwa) {static unsigned last = 0; nr = last++;}	//wprowadzam numeracje w konstruktorze, unikam w ten sposób powtórzeń
	bool operator==(const Owoc &owoc) const {return owoc.nr == nr;}				//elementem rozróżniającym owoce jest ich numer, a nie nazwa.
	bool operator!=(const Owoc &owoc) const {return !(operator==(owoc));}
	friend std::ostream& operator<<(std::ostream &o, const Owoc &owoc);
};

std::ostream& operator<<(std::ostream &o, const Owoc &owoc)
{
	o << owoc.nazwa_ << " nr " << owoc.nr;
	return o;
}

void przyklad3()
{
	std::list<Owoc> posiadane;
	std::list<Owoc> smaczne;

	//Tworze owoce
	Owoc A("Jablko");		//nr == 0
	Owoc B("Gruszka");		//1
	Owoc C("Morela");		//2
	Owoc D("Sliwka");		//3 dwie różne śliwki - rozróżniane po numerze.
	Owoc E("Sliwka");		//4
	Owoc F("Kiwi");			//5

	//Kopie tych owoców umieszczam w posiadanych.
	posiadane.push_back(A);
	posiadane.push_back(B);
	posiadane.push_back(C);
	posiadane.push_back(D);
	posiadane.push_back(E);
	posiadane.push_back(F);

	smaczne.push_back(B);
	smaczne.push_back(C);
	smaczne.push_back(E);		//tylko jedna śliwka należy do smacznych

	std::list<Owoc>::iterator iter;
	do
	{
		iter = std::find_first_of(posiadane.begin(), posiadane.end(), smaczne.begin(), smaczne.end());
		if (iter != posiadane.end())
		{
			std::cout << "Zjedzono smaczny owoc: " << *iter << std::endl;
			posiadane.erase(iter);			//zjadam więc usuwam z listy posiadanych
		}
	} while (iter != posiadane.end());
}

int main()
{
//Przykład 1
	std::cout << "Count words: " << countWords("Dlugi napis testowy z duza iloscia znakow.") << std::endl;

//Przykład 2
	std::string ZapisKolorow = "Zapis Kolorów Grafiki: R114G111B103";
	int pos = firstColor(ZapisKolorow,0);			//wykonuje wyszukiwanie na całym stringu, efektem jest zbędna interpretacja napisu wprowadzającego jako kolor
	std::cout << "Kolor " << ZapisKolorow[pos] << ": " << ZapisKolorow[pos + 1] << ZapisKolorow[pos + 2] << ZapisKolorow[pos + 3] << std::endl;
	pos = firstColor(ZapisKolorow,23);			//pomijam napis wprowadzający
	std::cout << "Kolor " << ZapisKolorow[pos] << ": " << ZapisKolorow[pos + 1] << ZapisKolorow[pos + 2] << ZapisKolorow[pos + 3] << std::endl;

//Przykład 3
	przyklad3();
	return 0;
}
