#include <systemc>

using namespace sc_core;
using namespace sc_dt;
using namespace std;

const sc_time EMPTY_TIME(8 * 3600, SC_SEC);
const sc_time FILL_TIME(5 * 60, SC_SEC);

SC_MODULE(gas_station) {
    SC_CTOR(gas_station): m_tank1(false), m_tank2(false), m_filling(false) {
        SC_THREAD(customer1_thread);
        sensitive << e_tank_filled;
        SC_THREAD(customer2_thread);
        sensitive << e_tank_filled;
        SC_METHOD(attendant_method);
        sensitive << e_request1 << e_request2;
        dont_initialize();
    }
private:
    sc_event e_request1, e_request2;
    sc_event e_tank_filled;
    void attendant_method();
    void customer1_thread();
    void customer2_thread();
    bool m_tank1, m_tank2, m_filling;
};

void gas_station::customer1_thread() {
    while (1) {
        m_tank1 = true;
        wait(EMPTY_TIME);
        m_tank1 = false;
        cout << sc_time_stamp() << ": Customer1 needs gas" << endl;
        do {
            e_request1.notify();
            wait();
        } while (m_tank1 == false) ;
    }
}

void gas_station::customer2_thread() {
    while (1) {
        m_tank2 = true;
        wait(EMPTY_TIME);
        m_tank2 = false;
        cout << sc_time_stamp() << ": Customer2 needs gas" << endl;
        do {
            e_request2.notify();
            wait();
        } while (m_tank2 == false) ;
    }
}

void gas_station::attendant_method() {
    if (!m_filling) {
        if (m_tank1 == false) {
            m_tank1 = true;
        }
        else if (m_tank2 == false) {
            m_tank2 = true;
        }
        cout << sc_time_stamp() << ": Filling tank" << endl;
        m_filling = true;
        next_trigger(FILL_TIME);
    } else {
        e_tank_filled.notify(SC_ZERO_TIME);
        cout << sc_time_stamp() << ": Filled tank" << endl;
        m_filling = false;
    }
}

int sc_main(int argc, char *argv[]) {
    gas_station s("s");
    sc_start(20 * 3600, SC_SEC);
    cin.get();
    return 0;
}