#include <list>
#include <mutex>
#include <thread>
#include <iostream>

using namespace std;

// blokada dla 3 obiektow, in/out

class Calc {
public:
    static const int TOKEN_END = 100;
	static const int NUM = 100;
    Calc() : in_(nullptr) {
        data_.push_back(0); //data is not empty at start
        data_.push_back(0);
    }
    void setIn(Calc* p) { in_ = p; }

    int read() {
        int ret = TOKEN_END;
        lock_guard lock(m_);
         if(!data_.empty() ) {
             ret = data_.front();
             data_.pop_front();
         }
         return ret;
    }
    void operator()() {
        for(int i=0;i<NUM;++i) {
            //tutaj sa obliczenia (kod nieistotny dla zadania)
            //lock_guard lock(m_);
			std::this_thread::sleep_for(std::chrono::milliseconds(10));

            if(in_) {
                int x = in_->read();
                if( x != TOKEN_END) {
                    //tutaj sa obliczenia (kod nieistotny dla zadania)
                    lock_guard lock(m_); // poprawna odpowiedz!
                    cout << "X:" << x << endl;
                    data_.push_back(x + 1);
                }
            }
        }
    }
private:
    Calc* in_;
    list<int> data_;
    mutex m_;
};

int main() {

    Calc c1, c2, c3;

    c1.setIn(&c3);
    c2.setIn(&c1);
    c3.setIn(&c2);

    thread thrd1( ref(c1) ), thrd2( ref(c2) ), thrd3( ref(c3) );

    thrd1.join();    thrd2.join();    thrd3.join();

    cout << "thrd1: " << c1.read() << endl;
    cout << "thrd2: " << c2.read() << endl;
    cout << "thrd3: " << c3.read() << endl;
}
