//	Paweł Sikorski
//	Przykład użycia algorytmu z biblioteki stl -
//		stable_partition

//template<class BidirectionalIterator, class Predcate>
//BidirectionalIterator stable_partition(	BidirectionalIterator first,
//											BidirectionalIterator last,
//											Predicate pred);

//stable_partition umieszcza wszystkie elementy podanego zbioru spełniające
//obiekt funkcyjny predykatu przed elementami, które go nie spełniają.
//Zachowane zostaje względne uporządkowanie elementów w każdej grupie.

//Dla porównania, algorytm partition także umieszcza wszystkie elementy podanego
//zbioru spełniające obiekt funkcyjny predykatu przed elementami, które go nie
//spełniają. Jednak w tym przypadku kolejność wewnętrzna nie musi być zachowana.

#include <iostream>		//cout
#include <algorithm>	//stable_partition
#include <vector>		//vector
#include <string>		//string
#include <cstdlib>		//rand
#include <ctime>		//time
using namespace std;

//używane typy wyliczeniowe
typedef enum {BASKETBALL, VOLEYBALL} InterestType;
typedef enum {MAN, WOMAN} SexType;
//Liczba rekordów
#define PEOPLE_NUM	40

//Klasa przedstawiająca osobę,
//	mężczyznę bądź kobietę,
//	interesującą się koszykówką bądź siatkówką
//	Dodatkowo każda osoba ma unikalny nr ID
//		(do jednoznacznego jej rozpoznania)
class Person{
private:
	static unsigned ID;
	static const string SexName[];
	static const string InterestName[];
	unsigned _myID;
	InterestType _hobby;
	SexType	_sex;
public:
	Person(InterestType h=BASKETBALL, SexType s=MAN): _myID(ID++),_hobby(h), _sex(s) {}
//	Dla metod Predicate.*
	SexType getSex() const	{return _sex;}
	InterestType getHobby() const	{return _hobby;}

	unsigned getID() const	{return _myID;}
	const string& getHobbyName() const	{return InterestName[_hobby];}
	const string& getSexName() const	{return SexName[_sex];}
//	Wypisz do strumienia
	friend ostream& operator<<(ostream& str,const Person& p){
		return str<<p.getID()<<"\t"<<p.getHobbyName()<<"\t"<<p.getSexName();
	}
};

//Inicializacja statycznych składowych klasy Person
unsigned Person::ID=1;
const string Person::SexName[]={"Mężczyzna","Kobieta"};
const string Person::InterestName[]={"Koszykówka","Siatkówka"};

//Klasa zbierająca funkcje sprawdzające odpowiednio
//płeć oraz zainteresowanie
class Predicate{
public:
	static bool sex(const Person &p){
		return (p.getSex()==WOMAN);
	}

	static bool hobby(const Person &p){
		return (p.getHobby()==BASKETBALL);
	}
};

void Print(vector<Person> & people);//Deklaracja

int main() {
	vector<Person> people;
	srand ( time(NULL) );
	cout<<"--------------------------------------\n"
		<<"Osoby ustawiają się w kolejkę do kas\n"
		<<"Z tym że jest jedna kolejka a dwie kasy\n"
		<<"(z różnymi biletami), a osoby różnej płci\n"
		<<"i o różnych zainteresowaniach przychodzą\n"
		<<"losowo.\n";
	for(unsigned i=0;i<PEOPLE_NUM;++i)	//wypełnianie kolejki
		people.push_back(Person(InterestType(rand() % 2),SexType(rand() % 2)));
	Print(people);

//	Iteratory, które będą wskazywały punkty graniczne zainteresowań
//	i płci w wektorze people;
	vector<Person>::iterator hobby_it,hobby_women_it,hobby_men_it;

//	Sortowanie listy względem hobby (płeć bez różnicy)
	hobby_it=stable_partition(people.begin(),people.end(),Predicate::hobby);
	cout<<"\nPo dzieleniu wzgledem hooby\n";
    Print(people);

//  Sortowanie list (części zainteresowanych koszykówką i siatkówką)
//  względem płci
	hobby_women_it=stable_partition(people.begin(),hobby_it,Predicate::sex);
	hobby_men_it=stable_partition(hobby_it,people.end(),Predicate::sex);
	cout<<"\nPo dzieleniu względem hobby i płci\n";
	Print(people);

//	Dzieki takiemu posortowaniu, zachowana jest kolejnosc przychodzacych ludzi oraz dodatkowo
//	zostali oni podzieleni pomiędzy dwa okienka (bilety koszykówka, bilety siatkówka).
//	Co więcej dzięki drugiemu sortowaniu nie tylko "występuje" podział pomiędzy okienkami,
//	ale także mężczyźni "przepuścili" kobiety na początek kolejek.

	return 0;
}

//Funkcja "drukująca" na dany strumień
void Print(vector<Person> & people){
	cout<<"------------------------------\n";
	cout<<"ID\tHOBBY\t\tPŁEC\n";
    cout<<"------------------------------\n";
    vector<Person>::const_iterator i;
    for(i = people.begin();i != people.end();++i)	cout << (*i) << "\n";
	cout<<"---------------------------------\n";
}
