#include #include #include #include #include using namespace std; const int wxID_START = 1001; // Funkcija vraca slucajan broj na intervalu od 0 do 1 double random() { return rand()/(1.0*RAND_MAX); } // Klasa dijagram stanja class statechart; // Apstraktna klasa stanja class state { protected: statechart* _sc; public: state(const statechart* sc):_sc(const_cast(sc)) {} virtual ~state() {} public: virtual void react() = 0; }; // Apstraktna klasa dogadjaj class event { protected: statechart* _sc; public: event(const statechart* sc):_sc(const_cast(sc)) {} virtual ~event() {} public: virtual void action() = 0; }; // ---------- DOGADJAJI ------------- // Procitana kartica class card_readable:public event { public: card_readable(const statechart* sc):event(sc) {} public: void action(); }; // Ucitan pin kartice class pin_read:public event { public: pin_read(const statechart* sc):event(sc) {} public: void action(); }; // Izabrana transakcija class transaction_chosen:public event { public: transaction_chosen(const statechart* sc):event(sc) {} public: void action(); }; // Transakcija je zavrsena class customer_finished:public event { public: customer_finished(const statechart* sc):event(sc) {} public: void action(); }; // Kartica nije procitana class card_not_readable:public event { public: card_not_readable(const statechart* sc):event(sc) {} public: void action(); }; // Otkazujem class cancel:public event { public: cancel(const statechart* sc):event(sc) {} public: void action(); }; // Jos jedna transakcija class another_transaction:public event { public: another_transaction(const statechart* sc):event(sc) {} public: void action(); }; // Pogresan PIN class invalid_pin:public event { public: invalid_pin(const statechart* sc):event(sc) {} public: void action(); }; // Previse pogresnih PIN-ova class too_many_invalid_pins:public event { public: too_many_invalid_pins(const statechart* sc):event(sc) {} public: void action() {} }; // ------------ STANJE -------------- // Citanje kartice class reading_card:public state { public: reading_card(const statechart* sc):state(sc) {} public: void react(); }; // Citanje PINa class reading_pin:public state { size_t _ip; public: reading_pin(const statechart* sc):state(sc),_ip(0) {} public: void react(); }; // Izabiranje transakcije class choosing_transaction:public state { public: choosing_transaction(const statechart* sc):state(sc) {} public: void react(); }; // Transakcija class performing_transaction:public state { public: performing_transaction(const statechart* sc):state(sc) {} public: void react(); }; // Vracanje kartice class ejecting_card:public state { public: ejecting_card(const statechart* sc):state(sc) {} public: void react(); }; // Dijagram stanja class statechart { bool _final; // Tekuce stanje state* _current; public: // Kontruktor statechart():_final(false),_current(nullptr) {} // Postavljamo pocetno stanje void initial(const state* s) { _current = const_cast(s); } // Tranzicija void transition(const event* e) { const_cast(e)->action(); delete const_cast(e); } public: // Postavi u finalno stanje i vrati da li je u finalnom stanju bool get_final() { return _final; } void set_final(const bool f) { _final = f; } // Postavi i vrati tekuce stanje void set_current(const state * s) { if(_current) delete _current; _current = const_cast(s); } state* get_current() const { return _current; } public: // Reakcija dijagrama stanja na promenu stanja void react() { _current->react(); } }; // Reakcija sistema na promenu stanja reading_card void reading_card::react() { double p = random(); if(p<=0.05) { _sc->transition(new card_not_readable(_sc)); } else { _sc->transition(new card_readable(_sc)); } } // Reakcija sistema na promenu stanja reading_card void reading_pin::react() { double p = random(); if(p<=0.10) { _sc->transition(new cancel(_sc)); } else if(p<=0.30) { _ip++; if(_ip<3) _sc->transition(new invalid_pin(_sc)); else { _sc->transition(new too_many_invalid_pins(_sc)); _sc->set_final(true); } } else { _sc->transition(new pin_read(_sc)); } } // Reakcija sistema na promenu stanja choosing_transaction void choosing_transaction::react() { double p = random(); if(p<=0.20) { _sc->transition(new cancel(_sc)); } else { _sc->transition(new transaction_chosen(_sc)); } } // Reakcija sistema na promenu stanja performing_transaction void performing_transaction::react() { double p = random(); if(p<=0.40) { _sc->transition(new another_transaction(_sc)); } else { _sc->transition(new customer_finished(_sc)); } } // Reakcija sistema na promenu stanja ejecting_card void ejecting_card::react() { _sc->set_final(true); } // Akcija dogadjaja card_readable void card_readable::action() { if(dynamic_cast(_sc->get_current())) { _sc->set_current(new reading_pin(_sc)); cout << "READING_PIN" << endl; } else { cerr << "Error" << std::endl; exit(1); } } // Akcija dogadjaja card_not_readable void card_not_readable::action() { if(dynamic_cast(_sc->get_current())) { _sc->set_current(new ejecting_card(_sc)); cout << "EJECTING_CARD" << endl; } else { cerr << "Error" << std::endl; exit(1); } } // Akcija dogadjaja pin_read void pin_read::action() { if(dynamic_cast(_sc->get_current())) { _sc->set_current(new choosing_transaction(_sc)); cout << "CHOOSING_TRANSACTION" << endl; } else { cerr << "Error" << std::endl; exit(1); } } // Akcija dogadjaja invalid_pin void invalid_pin::action() { if(dynamic_cast(_sc->get_current())) { _sc->set_current(new reading_pin(_sc)); cout << "READING_PIN" << endl; } else { cerr << "Error" << std::endl; exit(1); } } // Akcija dogadjaja cancel void cancel::action() { if(dynamic_cast(_sc->get_current()) || dynamic_cast(_sc->get_current())) { _sc->set_current(new ejecting_card(_sc)); cout << "EJECTING_CARD" << endl; } else { cerr << "Error" << std::endl; exit(1); } } // Akcija dogadjaja transaction_chosen void transaction_chosen::action() { if(dynamic_cast(_sc->get_current())) { _sc->set_current(new performing_transaction(_sc)); cout << "PERFORMING_TRANSACTION" << endl; } else { cerr << "Error" << std::endl; exit(1); } } // Akcija dogadjaja another_transaction void another_transaction::action() { if(dynamic_cast(_sc->get_current())) { _sc->set_current(new choosing_transaction(_sc)); cout << "CHOOSING_TRANSACTION" << endl; } else { cerr << "Error" << std::endl; exit(1); } } // Akcija dogadjaja customer_finished void customer_finished::action() { if(dynamic_cast(_sc->get_current())) { _sc->set_current(new ejecting_card(_sc)); cout << "EJECTING_CARD" << endl; } else { cerr << "Error" << std::endl; exit(1); } } struct Control { wxPanel* pPanel; // Objekat dijagrama stanja statechart *sc{nullptr}; void RunATM(wxPanel* pPanel) { wxPaintDC dc(pPanel); std::cout << "Refresh" << std::endl; wxSize size = pPanel->GetSize(); dc.SetBrush(*wxBLACK_BRUSH); dc.SetPen(*wxRED_PEN); dc.DrawCircle(size.GetWidth()/2,30,10); dc.DrawLine(size.GetWidth()/2,40,size.GetWidth()/2,60); if(sc && dynamic_cast(sc->get_current())!=nullptr) dc.SetBrush(*wxYELLOW_BRUSH); else dc.SetBrush(*wxRED_BRUSH); dc.DrawRoundedRectangle(size.GetWidth()/2-50,60,100,40,5); dc.DrawLabel("READING CARD",wxRect(size.GetWidth()/2-50,60,100,40),wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL); dc.DrawLine(size.GetWidth()/2,100,size.GetWidth()/2,120); dc.DrawText("Card readable",size.GetWidth()/2+5,103); if(sc && dynamic_cast(sc->get_current())!=nullptr) dc.SetBrush(*wxYELLOW_BRUSH); else dc.SetBrush(*wxRED_BRUSH); dc.DrawRoundedRectangle(size.GetWidth()/2-50,120,100,40,5); dc.DrawLabel("READING PIN",wxRect(size.GetWidth()/2-50,120,100,40),wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL); dc.DrawLine(size.GetWidth()/2,160,size.GetWidth()/2,180); dc.DrawText("PIN read",size.GetWidth()/2+5,163); if(sc && dynamic_cast(sc->get_current())!=nullptr) dc.SetBrush(*wxYELLOW_BRUSH); else dc.SetBrush(*wxRED_BRUSH); dc.DrawRoundedRectangle(size.GetWidth()/2-60,180,120,50,5); dc.DrawLabel("CHOOSING\nTRANSACTION",wxRect(size.GetWidth()/2-60,180,120,50),wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL); dc.DrawLine(size.GetWidth()/2,230,size.GetWidth()/2,250); dc.DrawText("Trans. chosen",size.GetWidth()/2+5,233); if(sc && dynamic_cast(sc->get_current())!=nullptr) dc.SetBrush(*wxYELLOW_BRUSH); else dc.SetBrush(*wxRED_BRUSH); dc.DrawRoundedRectangle(size.GetWidth()/2-60,250,120,50,5); dc.DrawLabel("PERFORMING\nTRANSACTION",wxRect(size.GetWidth()/2-60,250,120,50),wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL); dc.DrawLine(size.GetWidth()/2,300,size.GetWidth()/2,320); dc.DrawText("Cust. finished",size.GetWidth()/2+5,303); if(sc && dynamic_cast(sc->get_current())!=nullptr) dc.SetBrush(*wxYELLOW_BRUSH); else dc.SetBrush(*wxRED_BRUSH); dc.DrawRoundedRectangle(size.GetWidth()/2-60,320,120,50,5); dc.DrawLabel("EJECTING CARD",wxRect(size.GetWidth()/2-60,320,120,50),wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL); dc.DrawLine(size.GetWidth()/2,370,size.GetWidth()/2,397); dc.SetBrush(*wxBLACK_BRUSH); dc.DrawCircle(size.GetWidth()/2,410,10); dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawCircle(size.GetWidth()/2,410,13); // Card not readable dc.DrawLine(size.GetWidth()/2+50,80,size.GetWidth()/2+180,80); dc.DrawLine(size.GetWidth()/2+180,80,size.GetWidth()/2+180,410); dc.DrawText("Card not readable",size.GetWidth()/2+65,65); // Cancel dc.DrawLine(size.GetWidth()/2+50,140,size.GetWidth()/2+140,140); dc.DrawLine(size.GetWidth()/2+140,140,size.GetWidth()/2+140,410); dc.DrawText("Cancel",size.GetWidth()/2+65,125); // Cancel dc.DrawLine(size.GetWidth()/2+60,205,size.GetWidth()/2+100,205); dc.DrawLine(size.GetWidth()/2+100,205,size.GetWidth()/2+100,410); dc.DrawText("Cancel",size.GetWidth()/2+65,190); dc.DrawLine(size.GetWidth()/2+13,410,size.GetWidth()/2+180,410); // Too many invalid pins dc.DrawLine(size.GetWidth()/2-50,130,size.GetWidth()/2-160,130); dc.DrawLine(size.GetWidth()/2-160,130,size.GetWidth()/2-160,410); dc.DrawLine(size.GetWidth()/2-13,410,size.GetWidth()/2-160,410); dc.DrawRotatedText("Too many invalid pins", wxPoint(size.GetWidth()/2-180,320), 90); // Invalid pin dc.DrawLine(size.GetWidth()/2-80,130,size.GetWidth()/2-80,150); dc.DrawLine(size.GetWidth()/2-80,150,size.GetWidth()/2-50,150); dc.DrawText("Invalid PIN",size.GetWidth()/2-110,153); // Another transaction dc.DrawLine(size.GetWidth()/2-60,275,size.GetWidth()/2-100,275); dc.DrawLine(size.GetWidth()/2-100,275,size.GetWidth()/2-100,205); dc.DrawLine(size.GetWidth()/2-100,205,size.GetWidth()/2-60,205); dc.DrawRotatedText("Another\ntransaction", wxPoint(size.GetWidth()/2-135,270), 90); } void Start() { sc = new statechart; // Seme generatora slucajnih brojeva iniciramo vremenom. // Na ovaj nacin sa svakim izvresenjem programa dobijamo druge vrednosti stanja. srand(time(NULL)); // Postavljamo pocetno stanje sc->initial(new reading_card(sc)); cout << "READING_CARD" << endl; pPanel->Refresh(); pPanel->Update(); wxSleep(1); // Prolazimo kroz sva stanja dijagrama stanja dok ne dodjemo do finalnog while(!sc->get_final()) { sc->react(); pPanel->Refresh(); pPanel->Update(); wxSleep(1); } delete sc; sc = nullptr; pPanel->Refresh(); pPanel->Update(); cout << endl; } void ShowMainWindow() { wxFrame* pMainFrame = new wxFrame(nullptr,wxID_ANY,"Bankomat",wxDefaultPosition,wxSize(800,600)); wxBoxSizer* pSizer = new wxBoxSizer(wxVERTICAL); pPanel = new wxPanel(pMainFrame,wxID_ANY); wxButton* pStart = new wxButton(pMainFrame,wxID_START,"Start"); pSizer->Add(pPanel,1,wxEXPAND); pSizer->Add(pStart,0,wxEXPAND); pPanel->Bind(wxEVT_PAINT, [this](wxPaintEvent& ev) { RunATM(pPanel); }); pMainFrame->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [this](wxCommandEvent& event){ Start(); },wxID_START); pMainFrame->SetSizer(pSizer); pMainFrame->SetAutoLayout(true); pMainFrame->Show(); } } cont; int main(int argc,char *argv[]) { wxApp::SetInstance(new wxApp); if(wxEntryStart(argc,argv)) { cont.ShowMainWindow(); // Pokrecemo glavnu aplikacionu petlju wxTheApp->OnRun(); wxEntryCleanup(); } return 0; }