/*	Autor: Adrian Fiergolski EIKPE
	
	  Program prezentujący przyklad użycia Multimapy
Opis: Multimapa to posortowany kontener asocjacyjny, czyli zbiornik o zmiennej długości gromadzący dane,
	  które można dodawać i usuwać. Jest ona zbiornikiem parowym, a więc jej elementami są pary wartości: 
	  klucz i dana. Pierwszej wartości typu key_type, będącej kluczem multimapy, nie można zmieniać,
	  natomiast druga wartość danej jest przypisywalna (np.(*i).second=2). Elementów multimapy nie można
	  dodawać na konkretną pozycje, ponieważ ich kolejność ustalana jest wg danej klucz. Multimapa nie
	  jest unikalnym kontenerem asocjacyjnym, a więc dwa elementy mogą posiadać ten sam klucz.
*/

	 //Nagłówek z deklaracją Multimap'y
#include <map>	
	 //Nagłówek z deklaracją ostream_iterator
#include <iterator> 

#include <string>
#include <iostream>

using namespace std;

/*	  Alias multimapy przechowującej nazwy miesiąca według ich długości. Kluczem jest int - długość miesiąca 
	  w dniach; zaś przechowywaną wartością string - nazwa miesiąca. Trzeci parametr określa obiekt funkcyjny
	  porównujący dwa klucze w celu nadania porządku w kontenerze. Domyślnie jest to funktor less<T>, w przy-
	  kładzie zostanie zastosowany greater<T> - miesiące będą przechowywane od najdłuższego do najkrótszego.
	  Multimapa będzie korzystać z domyślnego allocatora (czwarty domyślny argument).
*/
typedef multimap<int, string, greater<int> > months_type;


/*	   Szablony z przeciążonymi operatorami << należy dołączyć do przestrzeni nazw std, w przeciwnym razie nie
	   byłyby wykorzystywane z powodu "Koenig Lookup" => www.gotw.ca/gotw/030.htm
*/
namespace std
{
/*	   Szablon przeciążenia operatora <<, który posłuży do wypisywania na standardowym wyjściu nazwy miesiąca
	   i jego długość, na podstawie pair<T,T>*/
	template <class First, class Second>   
		ostream& operator<<(ostream& out, const pair<First,Second>& p)
		{
			cout << p.second << " ma " << p.first << " dni";
			return out;
		}

/*	   Przeciążenie operatora <<, ktróre posłuży do wyśetlania na standardowym wyjściu zawartości multimapy.*/
	ostream& operator<<(ostream& out, months_type& m)
	{
/*	   Wykorzystanie copy z biblioteki stl,który kopiuje pewien zakres multimapy do ostram_iterator.
	   ostream_iterator jest iteratorem wyjścia (umożliwia tylko zapis wartości do danego składnika –
	   odczyt jest niemożliwy). Jego szablon wymaga zdefiniowania typu przechowywanych elementów 
	   w strumieniu. Konstruktor ostream_iterator wywoływane jest z parametrami, które definiują strumień
	   oraz char* dodawany na końcu każdego elementu.
	   Samo poruszanie się po multimapie zrealizowano, z wykorzystaniem jej iteratorów (m.begin(),m.end).
*/
		copy(m.begin(),m.end(), ostream_iterator<months_type::value_type>(cout,"\n"));
		return out;
	}
}

int main(void)
{
/*   Tworzenie multimapy miesięcy*/
    months_type months;

/*   Alias typu obiektu, pair<const key_type, data_type>, magazynowanego w multimapie*/
    typedef months_type::value_type value_type;

/*   Dodawanie miesięcy do multimapy: pierwszy w parze jest klucz, następnie sama wartość elementu*/
    months.insert(value_type(31, string("Styczen")));
    months.insert(value_type(28, string("Luty")));
    months.insert(value_type(31, string("Marzec")));
    months.insert(value_type(30, string("Kwiecien")));
    months.insert(value_type(31, string("Maj")));
    months.insert(value_type(30, string("Czerwiec")));
    months.insert(value_type(31, string("Lipiec")));
    months.insert(value_type(31, string("Sierpien")));
    months.insert(value_type(30, string("Wrzesien")));
    months.insert(value_type(31, string("Pazdziernik")));
    months.insert(value_type(30, string("Listopad")));
    months.insert(value_type(31, string("Grudzien")));


/*   Wyświetlenie zawartości multimapy - należy zauważyc,że miesiące będą one posortowanie zgodnie z za-
     danym wcześniej funktorem - od najdłuższego do najkrótszego. Metoda size() na rzecz multimapy zwraca
     jej rozmiar*/
    cout << "Wszystkie miesiace roku ("<< months.size()<<"):" << endl << months << endl;

/*   Wyszukanie miesięcy z 30 dniami (wyszukiwanie elementów o zadanym kluczu i zwrócenie pary iteratorów
     określających zakres wyników wyszukiwania)*/
    pair<months_type::iterator,months_type::iterator> p = months.equal_range(30);

/*   Wyświetlenie znalezionych miesięcy z wykorzystaniem copy. Metoda count() zwraca ilość elementów 
     o zadanym kluczu */
    cout << endl << "Miesiace z 30 dniami ("<<months.count(30)<<"):" << endl;
    copy(p.first,p.second, ostream_iterator<months_type::value_type>(cout,"\n"));

/*   Usuniecie części elementów z multimapy określonych przez iteratory z wykorzystaniem metody erase()
     i wyswietlenie zawartości multimapy*/ 	 
    months.erase(p.first,p.second);
    cout<<"\nRok pozbawiony miesiecy o 30 dniach ("<<months.size()<<"):\n"<<months<<endl;

    return 0;
}

/*   Wydruk programu:
		Wszystkie miesiace roku (12):
		Styczen ma 31 dni
		Marzec ma 31 dni
		Maj ma 31 dni
		Lipiec ma 31 dni
		Sierpien ma 31 dni
		Pazdziernik ma 31 dni
		Grudzien ma 31 dni
		Kwiecien ma 30 dni
		Czerwiec ma 30 dni
		Wrzesien ma 30 dni
		Listopad ma 30 dni
		Luty ma 28 dni


		Miesiace z 30 dniami (4):
		Kwiecien ma 30 dni
		Czerwiec ma 30 dni
		Wrzesien ma 30 dni
		Listopad ma 30 dni

		Rok pozbawiony miesiecy o 30 dniach (8):
		Styczen ma 31 dni
		Marzec ma 31 dni
		Maj ma 31 dni
		Lipiec ma 31 dni
		Sierpien ma 31 dni
		Pazdziernik ma 31 dni
		Grudzien ma 31 dni
		Luty ma 28 dni
*/


