/* Voorbeeldcode behorende bij het college "Programmeertechnieken",
 * LIACS, Universiteit Leiden.
 */

#include <iostream>

#include <vector>
#include <list>
#include <map>

#include <algorithm>


static void integer_container(void)
{
  std::vector<int> integers;

  /* Toevoegen aan container */
  integers.push_back(123);
  integers.push_back(643);
  integers.push_back(542);
  integers.push_back(234);
  integers.push_back(834);

  /* Itereren over de container */
  for (std::vector<int>::iterator it = integers.begin();
       it != integers.end(); ++it)
    std::cout << *it << " ";
  std::cout << std::endl;

  /* Sorteer de container van begin tot eind */
  std::sort(integers.begin(), integers.end());

  /* Draai de volgorde van de elementen in de container om */
  std::reverse(integers.begin(), integers.end());

  /* Zoek naar element 643 en vervang met 9234. */
  std::vector<int>::iterator tmpit =
      std::find(integers.begin(), integers.end(), 643);
  if (tmpit != integers.end())
    *tmpit = 9234;

  /* Zoek naar het kleinste element */
  std::vector<int>::iterator kleinste =
      std::min_element(integers.begin(), integers.end());
  std::cout << "Kleinste: " << *kleinste << std::endl;

  /* Druk elementen nogmaals af: gesorteerd en omgedraaid,
   * 643 vervangen met 9234.
   */
  for (std::vector<int>::iterator it = integers.begin();
       it != integers.end(); ++it)
    std::cout << *it << " ";
  std::cout << std::endl;

  /* Overschrijf de elementen in de vector */
  int i = 0;
  for (std::vector<int>::iterator it = integers.begin();
       it != integers.end(); ++it, ++i)
    *it = i;

  /* En zet op het scherm */
  for (std::vector<int>::iterator it = integers.begin();
       it != integers.end(); ++it)
    std::cout << *it << " ";
  std::cout << std::endl;
}

static void float_container(void)
{
  /* Initialiseer een vector met 4 floats met waarde 3.14. */
  std::vector<float> floats(4, 3.14);

  /* Nagaan! */
  for (std::vector<float>::iterator it = floats.begin();
       it != floats.end(); ++it)
    std::cout << *it << " ";
  std::cout << std::endl;

  /* Toegang via subscript werkt bij vectoren ook. */
  std::cout << "Subscript: " << floats[2] << std::endl;
}

static void list_example(void)
{
  /* std::list is een implementatie van een doubly-linked list.
   * Je werkt ermee net zoals met vector, maar er zit een andere
   * datastructuur achter (vector is in feite een dynamische array).
   */
  std::list<int> getallen;

  getallen.push_back(521);
  getallen.push_back(213);
  getallen.push_back(641);

  for (std::list<int>::iterator it = getallen.begin();
       it != getallen.end(); ++it)
    std::cout << *it << " ";
  std::cout << std::endl;
}

void pair_example(void)
{
  /* Een "pair" is een paar van twee waarden. Je kunt de waarden benaderen
   * met ".first" en ".second".
   */
  std::pair<std::string,int> leeftijd("Joop", 53);

  std::cout << leeftijd.first << ", "
            << leeftijd.second << std::endl << std::endl;

  /* std::make_pair is een hulpje om paren te instantieren. */
  leeftijd = std::make_pair("Karel", 23);
}

void vector_and_pair_example(void)
{
  /* We kunnen ook een vector maken bestaande uit paren. */

  /* Klassiek c++ vereist een spatie, C++11 niet meer */
  std::vector<std::pair<std::string, int> > leeftijden;

  leeftijden.push_back(std::make_pair("Joop", 53));
  leeftijden.push_back(std::make_pair("Karel", 23));
  leeftijden.push_back(std::make_pair("Ida", 32));

  /* Niet heel prettig voor de pols ...  zie het volgende voorbeeld. */
  for (std::vector<std::pair<std::string, int> >::const_iterator it = leeftijden.begin();
       it != leeftijden.end(); ++it)
    std::cout << it->first << ", " << it->second << std::endl;
  std::cout << std::endl;
}

static void vector_and_pair_typedef_example(void)
{
  /* Door gebruik te maken van typedef, besparen we onszelf later een
   * hoop typewerk.
   */
  typedef std::vector<std::pair<std::string, int> > LeeftijdVector;

  LeeftijdVector leeftijden;

  leeftijden.push_back(std::make_pair("Joop", 53));
  leeftijden.push_back(std::make_pair("Karel", 23));
  leeftijden.push_back(std::make_pair("Ida", 32));

  /* Al een stuk beter */
  for (LeeftijdVector::const_iterator it = leeftijden.begin();
       it != leeftijden.end(); ++it)
    std::cout << it->first << ", " << it->second << std::endl;
  std::cout << std::endl;

  /* Maar in C++11 codes kunnen we met nog minder volstaan. */
  for (const auto &pair : leeftijden)
    std::cout << pair.first << ", " << pair.second << std::endl;
  std::cout << std::endl;
}

static void map_example(void)
{
  /* Een "map" is een associatieve container, ofwel een container van
   * key-value paren. We kiezen "std::string" als het key-type en
   * int als het value-type.
   */
  typedef std::map<std::string, int> LeeftijdMap;

  LeeftijdMap leeftijden;

  /* Maak een paar en gebruik de insert methode */
  leeftijden.insert(std::make_pair("Joop", 53));

  /* Je mag ook subscript notatie gebruiken */
  leeftijden["Karel"] = 23;
  leeftijden["Ida"] = 32;

  /* Itereer over alle paren in de container. Let op: de keys zijn
   * gesorteerd, dus de volgorde is niet dezelfde als de volgorde van
   * toevoegen.
   */
  for (LeeftijdMap::const_iterator it = leeftijden.begin();
       it != leeftijden.end(); ++it)
    /* Iterator wijst naar een key-value paar in de map */
    std::cout << it->first << ", " << it->second << std::endl;
}


int main (void)
{
  integer_container();
  float_container();
  list_example();
  pair_example();
  vector_and_pair_example();
  vector_and_pair_typedef_example();
  map_example();

  return 0;
}