//: C10:MulticastCommand.cpp {RunByHand}
// Z knihy "Myslíme v jazyce C++, část 2" od Bruce Eckela a Chucka Allisona.
// (c) 1995-2004 MindView, Inc. Všechna práva vyhrazena.
// Přečtěte si podmínky používání zdrojových kódů umístěné v souboru 
// 'Licence.txt' dodávaném spolu s balíčkem kódu dostupným na www.MindView.net.
// Oddělení správy události pomocí vzoru Příkaz
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <cstdlib>
using namespace std;

// Rámec pro spouštění úkol:
class Ukol {
public:
  virtual void operace() = 0;
};

class SpoustecUkolu {
  static vector<Ukol*> ukoly;
  SpoustecUkolu() {} // Vytvořit z něho Jedináčka
  SpoustecUkolu& operator=(SpoustecUkolu&); // Zakázáno
  SpoustecUkolu(const SpoustecUkolu&); // Zakázáno
  static SpoustecUkolu su;
public:
  static void pridat(Ukol& t) { ukoly.push_back(&t); }
  static void spustit() {
    vector<Ukol*>::iterator it = ukoly.begin();
    while(it != ukoly.end())
      (*it++)->operace();
  }
};

SpoustecUkolu SpoustecUkolu::su;
vector<Ukol*> SpoustecUkolu::ukoly;

class SimulatorUdalosti {
  clock_t vytvoreni;
  clock_t zpozdeni;
public:
  SimulatorUdalosti() : vytvoreni(clock()) {
    zpozdeni = CLOCKS_PER_SEC/4 * (rand() % 20 + 1);
    cout << "zpozdeni = " << zpozdeni << endl;
  }
  bool vyvolana() {
    return clock() > vytvoreni + zpozdeni;
  }
};

// Třída generující asynchronní události:
class Tlacitko {
  bool stisknuto;
  string id;
  SimulatorUdalosti e; // na ukázku
public:
  Tlacitko(string nazev) : stisknuto(false), id(nazev) {}
  void stisknout() { stisknuto = true; }
  bool jeStisknuto() {
    if(e.vyvolana()) stisknout(); // Simuluje událost
    return stisknuto;
  }
  friend ostream&
  operator<<(ostream& os, const Tlacitko& b) {
    return os << b.id;
  }
};

// objekt Příkazu
class OverTlacitko : public Ukol {
  Tlacitko& tlacitko;
  bool zpracovano;
public:
  OverTlacitko(Tlacitko & b) : tlacitko(b), zpracovano(false) {}
  void operace() {
    if(tlacitko.jeStisknuto() && !zpracovano) {
      cout << tlacitko << " stisknuto" << endl;
      zpracovano = true;
    }
  }
};

// Procedury provádějící hlavní činnost. Je potřeba, 
// občas je "přerušit" aby zkontrolovaly stav tlačítek 
// a ostaní události:
void procedura1() {
  // Zde se provádí operace funkce procedura1
  // ...
  SpoustecUkolu::spustit(); // Zkontrolovat všechny události
}

void procedura2() {
  // Zde se provádí operace funkce procedura2
  // ...
  SpoustecUkolu::spustit(); // Zkontrolovat všechny události
}

void procedura3() {
  // Zde se provádí operace funkce procedura3
  // ...
  SpoustecUkolu::spustit(); // Zkontrolovat všechny události
}

int main() {
  srand(time(0)); // generátor náhodných čísel
  Tlacitko b1("Tlačítko 1"), b2("Tlačítko 2"), b3("Tlačítko 3");
  OverTlacitko cb1(b1), cb2(b2), cb3(b3);
  SpoustecUkolu::pridat(cb1);
  SpoustecUkolu::pridat(cb2);
  SpoustecUkolu::pridat(cb3);
  cout << "Ukončit stiskem Control-C" << endl;
  while(true) {
    procedura1();
    procedura2();
    procedura3();
  }
} ///:~
