/*
Opis: Program pokazujacy wykozystanie multiset.

Autor: Marcin Kłys
*/
#include <set>
#include <iostream>

using namespace std;

/*
      wypisz jest funkcja wypisująca wszystkie elementy z multizbioru przechowywujacego elementy typu int
*/
void wypisz( std::multiset<int> baza)
{
     std::cout << "( ";
     std::multiset<int>::iterator i=baza.begin();//deklaracja iteratora do danego multizbioru oraz ustawienie go na pierwszy element
     while( i!=baza.end() )       //pętla wykonuje się dopoki iterator nie wskazuje na element za ostatnim
     {
          std::cout << *i <<" ";  //wypisanie wartosci wskazywanej przez iterator
          ++i;                    //przestawienie iteratora na następny element       
     }
     std::cout << ")" << std::endl;
}

/*
     Komunikat - jest klasa ktorerj obiekty będą znajdowały sie w multizbiorze
*/
class Komunikat
{
      private:
             int priorytet;         //zakladam ze najwiekrzy priorytej jest gdy wartosc jest njmniejsza
             std::string opis;
      public:
             Komunikat(int p, std::string o):priorytet(p),opis(o) {}
             int getPriorytet()const {return priorytet;}
             std::string getOpis()const {return opis;}
             void setPriorytet(int nowy_priorytet) { priorytet=nowy_priorytet; }
};

/*
     Porownywacz - jest klasa za pomocą której bedą porównywane elementy typu Komunikat      
*/
class Porownywacz
{
      public:
             /*
                 operator funkcyjny porównujący elementy typu Komunikat tylko za pomocą priorytetu
             */
             bool operator()(Komunikat k1, Komunikat k2)
             {
                 return k1.getPriorytet()<k2.getPriorytet();
             }
};

/*
      wypisz jest funkcja wypisująca wszystkie elementy z multizbioru przechowywujacego elementy typu Komunikat
      */
void wypisz(std::multiset<Komunikat,Porownywacz> baza)
{
     cout << "( ";
     for( std::multiset<Komunikat>::iterator i=baza.begin(); i!=baza.end(); ++i)
          cout << (*i).getPriorytet() << (*i).getOpis() << " ";
     cout << ")" << std::endl;
}


int main(int argc, char *argv[])
{
/*
    czesc 1 - pokazanie dzialania wybranych metod
*/
    int tab[7]={2,8,6,1,4,8,0};
    multiset<int> baza1(tab,tab+7); //tworzony jest multizbior na podstawie zadanego przedzialu który jest tablica intów
    wypisz(baza1);
/*
program wypisuje:
( 0 1 2 4 6 8 8 )
*/

    multiset<int> baza2;
    baza2.insert( baza1.begin(), baza1.find(6) );  //tworzony jest multizbior na podstawie zadanego przedzialu <pierwszy element poprzedniego multizbioru; pierwsze wsytąpienie elementu rownego 6)
    wypisz(baza2);
/*
program wypisuje:
( 0 1 2 4 )
*/ 
  
    baza1.insert(4);                           //dodanie elementu o kluczu 4 
    baza1.erase(8);                            //usuwa wszystkie elementy o kluczu 8
    wypisz(baza1);
/*
program wypisuje:
( 0 1 2 4 4 6 )
*/
    
    cout << baza1.count(8) << " " << baza1.count(4) << " "<< baza1.size() << endl; //wypisuje liczbe elementow o kluczu 8, 4 oraz liczbe wszystkich elementow
/*
program wypisuje:
0 2 6
*/
    
    baza1.erase( baza1.find(4) );              //usuwa pierwszy element o kluczu 4
    wypisz(baza1);
/*
program wypisuje:
( 0 1 2 4 6 )
*/

    baza1.clear();
    if ( baza1.empty() ) cout << "multizbior jest pusty" << endl; 
/*
program wypisuje:
multizbior jest pusty
*/


   
/*
  czesc 2 - przykladowe zastosowanie - kolejka priorytetowa
  
  Do multizbioru dodajemy w dowolnej kolejnosci Komunikaty o roznych priorytetach, ktore trafiaja w odpowiednie miejsce:
  - komunikaty o wyższym priorytecie są przed komunikatami o nizszym priorytecie
  - komunikaty dodane wczesniej sa przed komunikatami dodanymi później (gdy mają taki sam priorytet)
*/
    
    multiset<Komunikat,Porownywacz> baza3;   //stworzenie multizbioru przechowywujacego Komunikaty, ktore sa porownywane za pomoca Porownywacz
    baza3.insert(Komunikat(1,"b"));          //dodawane są kolejne komunikaty z rożnym priorytetem i o roznych nazwach
    baza3.insert(Komunikat(2,"a"));
    baza3.insert(Komunikat(1,"a"));
    baza3.insert(Komunikat(1,"c"));
    baza3.insert(Komunikat(4,"d"));
    wypisz(baza3);
/*
program wypisuje:
( 1b 1a 1c 2a 4d )
*/
      
    multiset<Komunikat,Porownywacz>::iterator iter=baza3.begin();  //iter wskazuje na komunikat ktory powinien zostac obsluzony (jest najstarszy z komuniaktów mających najwyższy priorytet)
    cout << (*iter).getPriorytet() << (*iter).getOpis() << endl; 
    
/*
program wypisuje:
1b
*/
    system("PAUSE");
    return EXIT_SUCCESS;
}
