diff --git a/Ispiti/2026-07-09/PR2_2026-07-09_G1_Postavka.cpp b/Ispiti/2026-07-09/PR2_2026-07-09_G1_Postavka.cpp new file mode 100644 index 0000000..00db945 --- /dev/null +++ b/Ispiti/2026-07-09/PR2_2026-07-09_G1_Postavka.cpp @@ -0,0 +1,679 @@ +#include +using namespace std; + +string crt = "\n---------------------------------------------------------------------------------\n"; + +string PORUKA_TELEFON = crt + + "TELEFONE ISKLJUCITE I ODLOZITE U TORBU, DZEP ILI DRUGU LOKACIJU VAN " + + "DOHVATA.\n" + + "CESTO SE NA TELEFONIMA (PRO)NALAZE PROGRAMSKI KODOVI KOJI MOGU BITI " + + "ISKORISTENI ZA\n" + + "RJESAVANJE ISPITNOG ZADATKA, STO CE, U SLUCAJU PRONALASKA, BITI " + + "SANKCIONISANO.\n\n" + + "SVI KOD KOJIH BUDE PRONADJEN TELEFON ILI NEKI DRUGI UREDJAJ KOJI MOZE " + + "SADRZAVATI\n" + + "MATERIJAL ILI RJESENJA ISPITNIH ZADATAKA CE BITI UDALJENI SA ISPITA I " + + "BIT CE POKRENUT\n" + + "POSTUPAK PROTIV NJIH" + crt; + +string PORUKA_ISPIT = crt + + "0. PROVJERITE DA LI ZADACI PRIPADAJU VASOJ GRUPI (G1/G2)\n" + + "1. SVE KLASE SA DINAMICKOM ALOKACIJOM MORAJU IMATI ISPRAVAN " + + "DESTRUKTOR\n" + + "2. IZOSTAVLJANJE DESTRUKTORA ILI NJEGOVIH DIJELOVA BIT CE OZNACENO " + + "KAO TM\n" + + "3. ATRIBUTI, METODE I PARAMETRI MORAJU BITI IDENTICNI ONIMA U TESTNOJ " + + "MAIN FUNKCIJI,\n" + + " OSIM AKO POSTOJI JASNO OPISAN RAZLOG ZA MODIFIKACIJU\n" + + "4. IZUZETKE BACAJTE SAMO TAMO GDJE JE IZRICITO NAGLASENO\n" + + "5. SVE METODE KOJE SE POZIVAJU U MAIN-U MORAJU POSTOJATI.\n" + + " AKO NEMATE ZELJENU IMPLEMENTACIJU, OSTAVITE PRAZNO TIJELO ILI " + + "VRATITE DEFAULT VRIJEDNOST\n" + + "6. U MAIN FUNKCIJI MOZETE DODAVATI TESTNE PODATKE I POZIVE PO " + + "VLASTITOM IZBORU\n" + + "7. TESTIRAJTE PROGRAM U OBA MODA (F5 i Ctrl+F5)" + crt; + + +char* AlocirajTekst(const char* tekst) { + if (tekst == nullptr) + return nullptr; + + size_t velicina = strlen(tekst) + 1; + char* noviTekst = new char[velicina]; + + strcpy_s(noviTekst, velicina, tekst); + + return noviTekst; +} + + +enum VrstaDostave { + STANDARDNA, + BRZA, + MEDJUNARODNA +}; + +const char* VrstaDostaveOznake[] = { + "ST", + "BR", + "MD" +}; + +const char* VrstaDostaveNazivi[] = { + "STANDARDNA", + "BRZA", + "MEDJUNARODNA" +}; + + +enum StatusPosiljke { + KREIRANA, + PREUZETA, + U_TRANZITU, + ISPORUCENA, + OTKAZANA +}; + +const char* StatusPosiljkeNazivi[] = { + "KREIRANA", + "PREUZETA", + "U TRANZITU", + "ISPORUCENA", + "OTKAZANA" +}; + + +template +class Kolekcija { + T1* _elementi1[max]; + T2* _elementi2[max]; + int _trenutno; + +public: + Kolekcija() : _trenutno(0) { + for (int i = 0; i < max; i++) { + _elementi1[i] = nullptr; + _elementi2[i] = nullptr; + } + } + + int GetTrenutno() const { + return _trenutno; + } + + T1& GetElement1(int indeks) { + return *_elementi1[indeks]; + } + + T2& GetElement2(int indeks) { + return *_elementi2[indeks]; + } + + const T1& GetElement1(int indeks) const { + return *_elementi1[indeks]; + } + + const T2& GetElement2(int indeks) const { + return *_elementi2[indeks]; + } + + T1& operator[](int indeks) { + return *_elementi1[indeks]; + } + + friend ostream& operator<<(ostream& COUT, const Kolekcija& obj) { + for (int i = 0; i < obj.GetTrenutno(); i++) + COUT << obj.GetElement1(i) << " " + << obj.GetElement2(i) << endl; + + return COUT; + } + + ~Kolekcija() { + for (int i = 0; i < _trenutno; i++) { + delete _elementi1[i]; + delete _elementi2[i]; + + _elementi1[i] = nullptr; + _elementi2[i] = nullptr; + } + + _trenutno = 0; + } +}; + + +class DatumVrijeme { + int* _dan, * _mjesec, * _godina, * _sati, * _minute; + +public: + DatumVrijeme( + int dan = 1, + int mjesec = 1, + int godina = 2000, + int sati = 0, + int minute = 0) { + + _dan = new int(dan); + _mjesec = new int(mjesec); + _godina = new int(godina); + _sati = new int(sati); + _minute = new int(minute); + } + + friend ostream& operator<<(ostream& COUT, const DatumVrijeme& obj) { + //ToString vraca datum i vrijeme u formatu DD.MM.GGGG HH:MM, + COUT << obj.ToString(); + + return COUT; + } + + ~DatumVrijeme() { + delete _dan; + delete _mjesec; + delete _godina; + delete _sati; + delete _minute; + + _dan = _mjesec = _godina = _sati = _minute = nullptr; + } +}; + + +class Posiljka { + char* _oznaka; + char* _sadrzaj; + char* _imePrezimePrimaoca; + char* _emailPrimaoca; + VrstaDostave _vrstaDostave; + int _redniBroj; + + Kolekcija _statusi; + + void Dealociraj() { + delete[] _oznaka; + delete[] _sadrzaj; + delete[] _imePrezimePrimaoca; + delete[] _emailPrimaoca; + + _oznaka = _sadrzaj = _imePrezimePrimaoca = + _emailPrimaoca = nullptr; + } + +public: + const char* GetOznaka() const { + return _oznaka; + } + + const char* GetSadrzaj() const { + return _sadrzaj; + } + + const char* GetImePrezimePrimaoca() const { + return _imePrezimePrimaoca; + } + + const char* GetEmailPrimaoca() const { + return _emailPrimaoca; + } + + VrstaDostave GetVrstaDostave() const { + return _vrstaDostave; + } + + int GetRedniBroj() const { + return _redniBroj; + } + + Kolekcija& GetStatusi() { + return _statusi; + } + + StatusPosiljke GetTrenutniStatus() const { + return _statusi.GetElement1(_statusi.GetTrenutno() - 1); + } + + friend ostream& operator<<(ostream& COUT, const Posiljka& obj) { + // ToString vraca podatke u formatu: + // oznaka | ime i prezime | vrsta dostave | sadrzaj | trenutni status + // BH-BR-0042-AB | Amina Buric | BRZA | Dokumenti | KREIRANA + + COUT << obj.ToString(); + + return COUT; + } + + ~Posiljka() { + Dealociraj(); + } +}; + + +class DostavnaSluzba { + char* _naziv; + vector _posiljke; + +public: + DostavnaSluzba(const char* naziv = "") { + _naziv = AlocirajTekst(naziv); + } + + const char* GetNaziv() const { + return _naziv; + } + + vector& GetPosiljke() { + return _posiljke; + } + + ~DostavnaSluzba() { + delete[] _naziv; + _naziv = nullptr; + } +}; + + +const char* GetOdgovorNaPrvoPitanje() { + cout << "Pitanje -> Pojasnite da li se svako nasljedjivanje moze " + << "posmatrati kao polimorfizam i obrnuto? Navedite konkretne " + << "primjere.\n"; + + return "Odgovor -> OVDJE UNESITE VAS ODGOVOR"; +} + + +const char* GetOdgovorNaDrugoPitanje() { + cout << "Pitanje -> Pojasnite razloge kojima bi se implementator " + << "klase mogao voditi pri donosenju odluke da sve metode u klasi " + << "(ne)proglasi virtualnim?\n"; + + return "Odgovor -> OVDJE UNESITE VAS ODGOVOR"; +} + + +int main() { + cout << PORUKA_TELEFON; + cin.get(); + + cout << PORUKA_TELEFON; + cin.get(); + + cout << PORUKA_ISPIT; + cin.get(); + + system("cls"); + + cout << GetOdgovorNaPrvoPitanje() << crt; + cin.get(); + + cout << GetOdgovorNaDrugoPitanje() << crt; + cin.get(); + + + /* + Funkcija GenerisiOznaku generise oznaku posiljke u formatu: BH-VD-BBBB-IN + Potpis funkcije treba biti: + string GenerisiOznaku(const char* imePrezime, int redniBroj, + VrstaDostave vrstaDostave) + BH -> fiksna oznaka drzave, + VD -> vrsta dostave: ST (standardna), BR (brza), MD (medjunarodna), + BBBB -> redni broj posiljke popunjen nulama na slobodnim mjestima, + IN -> inicijali imena i prezimena primaoca. + Kod imena koje sadrzi vise rijeci koriste se inicijal prve i posljednje + rijeci. Redni broj mora biti u rasponu 1-9999. + Za neispravne podatke funkcija vraca "BH-XX-0000-XX". + */ + + if (GenerisiOznaku("Amina Buric", 42, BRZA) == "BH-BR-0042-AB") + cout << "Oznaka OK" << crt; + + if (GenerisiOznaku("Goran Skondric", 7, STANDARDNA) == + "BH-ST-0007-GS") + cout << "Oznaka OK" << crt; + + if (GenerisiOznaku("Ana Marija Kovac", 156, MEDJUNARODNA) == + "BH-MD-0156-AK") + cout << "Oznaka OK" << crt; + + if (GenerisiOznaku("Amina", 42, BRZA) == "BH-XX-0000-XX" && + GenerisiOznaku("Amina Buric", 0, BRZA) == "BH-XX-0000-XX" && + GenerisiOznaku("Amina Buric", 10000, BRZA) == "BH-XX-0000-XX" && + GenerisiOznaku("Amina Buric", 42, (VrstaDostave)99) == + "BH-XX-0000-XX") + cout << "Neispravni podaci za oznaku OK" << crt; + + + /* + Koristeci regex, funkcija ValidirajOznaku provjerava da li je oznaka + zapisana u prethodno definisanom formatu. Dozvoljene su iskljucivo oznake + vrsta ST, BR i MD, redni broj mora imati cetiri cifre i ne moze biti 0000, + a inicijali moraju biti zapisani velikim slovima. + Potpis funkcije treba biti: + bool ValidirajOznaku(const string& oznaka) + */ + + if (ValidirajOznaku("BH-BR-0042-AB")) + cout << "OZNAKA VALIDNA" << crt; + + if (!ValidirajOznaku("BH-EX-0042-AB") && + !ValidirajOznaku("BH-BR-042-AB") && + !ValidirajOznaku("BH-BR-0042-Ab") && + !ValidirajOznaku("BH-BR-0000-AB") && + !ValidirajOznaku("bh-BR-0042-AB")) + cout << "OZNAKA NIJE VALIDNA" << crt; + + if (ValidirajOznaku(GenerisiOznaku("Maid Ramic", 284, BRZA))) + cout << "GENERISANA OZNAKA VALIDNA" << crt; + + + Kolekcija brojevi; + + brojevi.Dodaj(10, "Deset"); + brojevi.Dodaj(20, "Dvadeset"); + brojevi.Dodaj(30, "Trideset"); + + cout << brojevi << crt; + + + /* + DodajNaPoziciju dodaje novi par na lokaciju/indeks definisanu + prvim parametrom, + pomjera postojece pokazivace udesno i vraca trenutno stanje + kolekcije (izmijenjeni tj. prosireni objekat). + U slucaju popunjene kolekcije ili neispravne lokacije potrebno je + baciti izuzetak. + */ + + Kolekcija prosireniBrojevi = + brojevi.DodajNaPoziciju(1, 15, "Petnaest"); + + cout << prosireniBrojevi << crt; + + + /* + UkloniSaPozicije uklanja par sa proslijedjene pozicije/indeksa, + preostale elemente + pomjera ulijevo i vraca uklonjeni par u obliku pair. + Za poziciju izvan opsega baca se izuzetak. + */ + + pair uklonjeni = + prosireniBrojevi.UkloniSaPozicije(2); + + cout << "Uklonjeno: " << uklonjeni.first << " " + << uklonjeni.second << crt; + + cout << "Preostali elementi:" << crt + << prosireniBrojevi; + + try { + prosireniBrojevi.UkloniSaPozicije(10); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + + + try { + Kolekcija punaKolekcija; + + punaKolekcija.Dodaj(1, "Jedan"); + punaKolekcija.Dodaj(2, "Dva"); + punaKolekcija.Dodaj(3, "Tri"); + + punaKolekcija.DodajNaPoziciju(1, 4, "Cetiri"); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + + + Kolekcija kopijaBrojeva = brojevi; + + kopijaBrojeva[0] = 100; + + Kolekcija dodijeljeniBrojevi; + + dodijeljeniBrojevi = brojevi; + + dodijeljeniBrojevi[1] = 200; + + cout << "Original:" << crt << brojevi; + cout << "Kopija:" << crt << kopijaBrojeva; + cout << "Dodijeljeni objekat:" << crt << dodijeljeniBrojevi; + + + DatumVrijeme kreirana(1, 7, 2026, 8, 0); + DatumVrijeme preuzeta(1, 7, 2026, 9, 0); + DatumVrijeme tranzit(1, 7, 2026, 10, 0); + DatumVrijeme isporucena(1, 7, 2026, 11, 0); + + + /* + ToString vraca datum i vrijeme u formatu DD.MM.GGGG HH:MM, + ukljucujuci + pocetne nule. + */ + + cout << kreirana.ToString() << crt; //01.07.2026 08:00 + + if (preuzeta > kreirana) + cout << "Vrijeme preuzimanja je nakon vremena kreiranja" << crt; + + DatumVrijeme kopijaPreuzeta(preuzeta); + + if (kopijaPreuzeta == preuzeta && !(kreirana == preuzeta)) + cout << "Provjera vremena, OK." << crt; + + + /* + Konstruktor Posiljke generise oznaku i evidentira pocetni status + KREIRANA + sa proslijedjenim vremenom kreiranja. + */ + + Posiljka dokumenti( + "Dokumenti", + "Amina Buric", + "amina@fit.ba", + BRZA, + 42, + kreirana + ); + + Posiljka knjige( + "Knjige", + "Goran Skondric", + "goran@fit.ba", + STANDARDNA, + 7, + kreirana + ); + + Posiljka oprema( + "Oprema", + "Ana Marija Kovac", + "ana@fit.ba", + MEDJUNARODNA, + 156, + kreirana + ); + + + /* + ToString vraca podatke u formatu: + oznaka | ime i prezime | vrsta dostave | sadrzaj | trenutni status + BH-BR-0042-AB | Amina Buric | BRZA | Dokumenti | KREIRANA + */ + + cout << dokumenti.ToString() << crt; + + if (dokumenti.ToString() == + "BH-BR-0042-AB | Amina Buric | BRZA | Dokumenti | KREIRANA") + cout << "Posiljka ToString OK" << crt; + + + /* + DodajStatus dodaje status samo ako je vrijeme vece od vremena + posljednjeg statusa i ako je promjena statusa dozvoljena. + Dozvoljen slijed statusa je: KREIRANA -> PREUZETA -> U_TRANZITU -> + ISPORUCENA + OTKAZANA se moze evidentirati iz bilo kojeg statusa koji nije zavrsni. + Nakon statusa ISPORUCENA ili OTKAZANA nisu dozvoljene nove promjene. + Preskakanje, ponavljanje statusa i hronoloski neispravno vrijeme vracaju + false, bez izmjene kolekcije statusa. + */ + + if (dokumenti.DodajStatus(PREUZETA, preuzeta)) + cout << "Status PREUZETA dodan" << crt; + + if (dokumenti.DodajStatus(U_TRANZITU, tranzit)) + cout << "Status U TRANZITU dodan" << crt; + + if (dokumenti.DodajStatus(ISPORUCENA, isporucena)) + cout << "Status ISPORUCENA dodan" << crt; + + if (!dokumenti.DodajStatus(OTKAZANA, isporucena)) + cout << "Promjena zavrsnog statusa nije dozvoljena" << crt; + + if (!knjige.DodajStatus(U_TRANZITU, preuzeta)) + cout << "Preskakanje statusa nije dozvoljeno" << crt; + + if (oprema.DodajStatus(OTKAZANA, preuzeta)) + cout << "Posiljka otkazana" << crt; + + + Posiljka kopijaDokumenata = dokumenti; + + cout << kopijaDokumenata << crt; + + + DostavnaSluzba brzaPosta("Brza posta"); + + + /* + DodajPosiljku dodaje posiljku u dostavnu sluzbu. Nije dozvoljeno dodati + dvije posiljke sa istim rednim brojem ili istom oznakom. U slucaju + duplikata metoda baca izuzetak. + */ + + brzaPosta.DodajPosiljku(knjige); + brzaPosta.DodajPosiljku(oprema); + + try { + brzaPosta.DodajPosiljku(knjige); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + + + /* + PronadjiPosiljku vraca pokazivac na posiljku sa proslijedjenom oznakom. + Ako posiljka nije pronadjena, metoda vraca nullptr. + */ + + string oznakaKnjige = knjige.GetOznaka(); + + Posiljka* pronadjena = + brzaPosta.PronadjiPosiljku(oznakaKnjige); + + if (pronadjena != nullptr) + cout << "Pronadjena posiljka: " + << pronadjena->GetOznaka() << crt; + + if (brzaPosta.PronadjiPosiljku("BH-ST-9999-XX") == nullptr) + cout << "Nepostojeca posiljka nije pronadjena" << crt; + + + /* + EvidentirajStatus pronalazi posiljku na osnovu oznake i pokusava + dodati + novi status koristeci pravila metode DodajStatus. + Nakon svakog uspjesno evidentiranog statusa potrebno je u zasebnom + threadu + poslati obavijest primaocu. Obavijest se ne salje ako posiljka ne + postoji ili status nije dodan, te u tim slucajevima metoda vraca + false. + Primjer sadrzaja obavijesti: + ------------------------------------------------------------------ + --------------- + To: goran@fit.ba + From: info@brzaposta.ba + Subject: Promjena statusa posiljke + Postovani Goran Skondric, + Posiljka BH-ST-0007-GS je promijenila status u PREUZETA. + Vrijeme evidentiranja: 01.07.2026 09:00 + Hvala sto koristite nase usluge. + BrzaPosta Tim + ------------------------------------------------------------------ + --------------- + */ + + if (brzaPosta.EvidentirajStatus( + oznakaKnjige, + PREUZETA, + preuzeta)) + cout << "Status evidentiran i obavijest poslana" << crt; + + if (!brzaPosta.EvidentirajStatus( + oznakaKnjige, + ISPORUCENA, + isporucena)) + cout << "Obavijest nije poslana za neispravnu promjenu " + << "statusa" << crt; + + if (!brzaPosta.EvidentirajStatus( + "NEPOSTOJECA", + PREUZETA, + preuzeta)) + cout << "Obavijest nije poslana za nepostojecu posiljku" + << crt; + + + /* + PosiljkePoStatusu vraca vector pokazivaca na sve posiljke ciji trenutni + status odgovara proslijedjenom statusu. + */ + + vector preuzetePosiljke = + brzaPosta.PosiljkePoStatusu(PREUZETA); + + for (auto posiljka : preuzetePosiljke) + cout << posiljka->GetOznaka() << " -> " + << StatusPosiljkeNazivi[ + (int)posiljka->GetTrenutniStatus() + ] + << crt; + + + /* + StatistikaPoStatusu vraca kolekciju koja za svaki status, + redoslijedom + definisanim enumom StatusPosiljke, sadrzi status i broj posiljki koje se + trenutno nalaze u tom statusu. U rezultat se dodaje svih pet statusa, + ukljucujuci i one za koje je broj posiljki jednak nuli. + */ + + Kolekcija statistika = + brzaPosta.StatistikaPoStatusu(); + + for (int i = 0; i < statistika.GetTrenutno(); i++) + cout << StatusPosiljkeNazivi[ + (int)statistika.GetElement1(i) + ] + << " -> " + << statistika.GetElement2(i) + << crt; + + + DostavnaSluzba kopijaSluzbe = brzaPosta; + + cout << kopijaSluzbe.GetNaziv() << " ima " + << kopijaSluzbe.GetPosiljke().size() + << " posiljki" << crt; + + cin.get(); + + return 0; +} diff --git "a/Ispiti/2026-07-09/PR2_2026-07-09_G1_Rje\305\241enje.cpp" "b/Ispiti/2026-07-09/PR2_2026-07-09_G1_Rje\305\241enje.cpp" new file mode 100644 index 0000000..e633287 --- /dev/null +++ "b/Ispiti/2026-07-09/PR2_2026-07-09_G1_Rje\305\241enje.cpp" @@ -0,0 +1,1020 @@ +// vela havle et + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +string crt = "\n---------------------------------------------------------------------------------\n"; + +string PORUKA_TELEFON = crt + +"TELEFONE ISKLJUCITE I ODLOZITE U TORBU, DZEP ILI DRUGU LOKACIJU VAN " + +"DOHVATA.\n" + +"CESTO SE NA TELEFONIMA (PRO)NALAZE PROGRAMSKI KODOVI KOJI MOGU BITI " + +"ISKORISTENI ZA\n" + +"RJESAVANJE ISPITNOG ZADATKA, STO CE, U SLUCAJU PRONALASKA, BITI " + +"SANKCIONISANO.\n\n" + +"SVI KOD KOJIH BUDE PRONADJEN TELEFON ILI NEKI DRUGI UREDJAJ KOJI MOZE " + +"SADRZAVATI\n" + +"MATERIJAL ILI RJESENJA ISPITNIH ZADATAKA CE BITI UDALJENI SA ISPITA I " + +"BIT CE POKRENUT\n" + +"POSTUPAK PROTIV NJIH" + crt; + +string PORUKA_ISPIT = crt + +"0. PROVJERITE DA LI ZADACI PRIPADAJU VASOJ GRUPI (G1/G2)\n" + +"1. SVE KLASE SA DINAMICKOM ALOKACIJOM MORAJU IMATI ISPRAVAN " + +"DESTRUKTOR\n" + +"2. IZOSTAVLJANJE DESTRUKTORA ILI NJEGOVIH DIJELOVA BIT CE OZNACENO " + +"KAO TM\n" + +"3. ATRIBUTI, METODE I PARAMETRI MORAJU BITI IDENTICNI ONIMA U TESTNOJ " + +"MAIN FUNKCIJI,\n" + +" OSIM AKO POSTOJI JASNO OPISAN RAZLOG ZA MODIFIKACIJU\n" + +"4. IZUZETKE BACAJTE SAMO TAMO GDJE JE IZRICITO NAGLASENO\n" + +"5. SVE METODE KOJE SE POZIVAJU U MAIN-U MORAJU POSTOJATI.\n" + +" AKO NEMATE ZELJENU IMPLEMENTACIJU, OSTAVITE PRAZNO TIJELO ILI " + +"VRATITE DEFAULT VRIJEDNOST\n" + +"6. U MAIN FUNKCIJI MOZETE DODAVATI TESTNE PODATKE I POZIVE PO " + +"VLASTITOM IZBORU\n" + +"7. TESTIRAJTE PROGRAM U OBA MODA (F5 i Ctrl+F5)" + crt; + + +char* AlocirajTekst(const char* tekst) { + if (tekst == nullptr) + return nullptr; + + size_t velicina = strlen(tekst) + 1; + char* noviTekst = new char[velicina]; + + strcpy_s(noviTekst, velicina, tekst); + + return noviTekst; +} + + + +enum VrstaDostave { + STANDARDNA, + BRZA, + MEDJUNARODNA +}; + +const char* VrstaDostaveOznake[] = { + "ST", + "BR", + "MD" +}; + +const char* VrstaDostaveNazivi[] = { + "STANDARDNA", + "BRZA", + "MEDJUNARODNA" +}; + + +enum StatusPosiljke { + KREIRANA, + PREUZETA, + U_TRANZITU, + ISPORUCENA, + OTKAZANA +}; + +const char* StatusPosiljkeNazivi[] = { + "KREIRANA", + "PREUZETA", + "U TRANZITU", + "ISPORUCENA", + "OTKAZANA" +}; + + +string GenerisiOznaku(const char* imePrezime, int redniBroj, VrstaDostave vrstaDostave) { + if (redniBroj < 1 || redniBroj > 9999) return "BH-XX-0000-XX"; + if(vrstaDostave MEDJUNARODNA) return "BH-XX-0000-XX"; + + std::ostringstream buffer; + string s_imePrezime = imePrezime; + size_t lastSpaceIndex = s_imePrezime.find_last_of(' '); + + // find_last_of() returna string::npos ako nije proslo || gleda dal je zadnji space jednak zadnjem karakteru u stringu + if (lastSpaceIndex == string::npos || lastSpaceIndex == s_imePrezime.size() - 1) { + return "BH-XX-0000-XX"; + } + + buffer << "BH-" << VrstaDostaveOznake[vrstaDostave] << "-" << setfill('0') << setw(4) << redniBroj << "-" << imePrezime[0] << imePrezime[lastSpaceIndex + 1]; + + return buffer.str(); +} + +bool ValidirajOznaku(const string& oznaka) { + return regex_match(oznaka, regex("BH-(ST|BR|MD)-(?!0000)[0-9]{4}-([A-Z]{2})")); +} + + +template +class Kolekcija { + T1* _elementi1[max]; + T2* _elementi2[max]; + int _trenutno; + +public: + Kolekcija() : _trenutno(0) { + for (int i = 0; i < max; i++) { + _elementi1[i] = nullptr; + _elementi2[i] = nullptr; + } + } + + Kolekcija(const Kolekcija& obj) { + // ovo radim jer _trenutno moze biti 3, a max 10 npr tako da se sve mora inicijalizirati, ako ne budes to uradio sjebat ces destruktor jer ce pokusat obrisat nesto sto ne postoji uopste + for (int i = 0; i < max; i++) { + _elementi1[i] = nullptr; + _elementi2[i] = nullptr; + } + + _trenutno = obj._trenutno; + for (int i = 0; i < _trenutno; i++) { + _elementi1[i] = new T1(*obj._elementi1[i]); + _elementi2[i] = new T2(*obj._elementi2[i]); + } + } + + Kolekcija& operator=(const Kolekcija& obj) { + if (this == &obj) return *this; + for (int i = 0; i < _trenutno; i++) { + delete _elementi1[i]; + delete _elementi2[i]; + + _elementi1[i] = nullptr; + _elementi2[i] = nullptr; + } + + _trenutno = obj._trenutno; + + for (int i = 0; i < _trenutno; i++) { + _elementi1[i] = new T1(*obj._elementi1[i]); + _elementi2[i] = new T2(*obj._elementi2[i]); + } + + return *this; + } + + + int GetTrenutno() const { + return _trenutno; + } + + T1& GetElement1(int indeks) { + return *_elementi1[indeks]; + } + + T2& GetElement2(int indeks) { + return *_elementi2[indeks]; + } + + const T1& GetElement1(int indeks) const { + return *_elementi1[indeks]; + } + + const T2& GetElement2(int indeks) const { + return *_elementi2[indeks]; + } + + T1& operator[](int indeks) { + return *_elementi1[indeks]; + } + + friend ostream& operator<<(ostream& COUT, const Kolekcija& obj) { + for (int i = 0; i < obj.GetTrenutno(); i++) + COUT << obj.GetElement1(i) << " " + << obj.GetElement2(i) << endl; + + return COUT; + } + + ~Kolekcija() { + for (int i = 0; i < _trenutno; i++) { + delete _elementi1[i]; + delete _elementi2[i]; + + _elementi1[i] = nullptr; + _elementi2[i] = nullptr; + } + + _trenutno = 0; + } + + void Dodaj(T1 el1, T2 el2) { + if (_trenutno >= max) return; + _elementi1[_trenutno] = new T1(el1); + _elementi2[_trenutno] = new T2(el2); + + _trenutno++; + } + + + Kolekcija& DodajNaPoziciju(int pos, T1 el1, T2 el2) { + + if (_trenutno >= max || pos < 0 || pos > _trenutno) { + throw exception("invalid arguments"); + } + + for (int i = _trenutno; i > pos; i--) { + _elementi1[i] = _elementi1[i - 1]; + _elementi2[i] = _elementi2[i - 1]; + } + + _elementi1[pos] = new T1(el1); + _elementi2[pos] = new T2(el2); + _trenutno++; + + return *this; + } + + + pair UkloniSaPozicije(int pos) { + pair par; + + if (pos < 0 || pos >= _trenutno) + throw exception("invalid pos"); + + par.first = *_elementi1[pos]; + par.second = *_elementi2[pos]; + + delete _elementi1[pos]; + delete _elementi2[pos]; + + for (int i = pos; i < _trenutno - 1; i++) { + _elementi1[i] = _elementi1[i + 1]; + _elementi2[i] = _elementi2[i + 1]; + } + + + _elementi1[_trenutno - 1] = nullptr; + _elementi2[_trenutno - 1] = nullptr; + _trenutno--; + + + return par; + } +}; + + +class DatumVrijeme { + int* _dan, * _mjesec, * _godina, * _sati, * _minute; + +public: + DatumVrijeme( + int dan = 1, + int mjesec = 1, + int godina = 2000, + int sati = 0, + int minute = 0) { + + _dan = new int(dan); + _mjesec = new int(mjesec); + _godina = new int(godina); + _sati = new int(sati); + _minute = new int(minute); + } + + + DatumVrijeme(const DatumVrijeme& obj) { + _dan = new int(*obj._dan); + _mjesec = new int(*obj._mjesec); + _godina = new int(*obj._godina); + _sati = new int(*obj._sati); + _minute = new int(*obj._minute); + } + + DatumVrijeme& operator=(const DatumVrijeme& obj) { + if (this == &obj) return *this; + delete _dan; + delete _mjesec; + delete _godina; + delete _sati; + delete _minute; + + _dan = _mjesec = _godina = _sati = _minute = nullptr; + + _dan = new int(*obj._dan); + _mjesec = new int(*obj._mjesec); + _godina = new int(*obj._godina); + _sati = new int(*obj._sati); + _minute = new int(*obj._minute); + return *this; + } + + friend ostream& operator<<(ostream& COUT, const DatumVrijeme& obj) { + //ToString vraca datum i vrijeme u formatu DD.MM.GGGG HH:MM, + COUT << obj.ToString(); + + return COUT; + } + + ~DatumVrijeme() { + delete _dan; + delete _mjesec; + delete _godina; + delete _sati; + delete _minute; + + _dan = _mjesec = _godina = _sati = _minute = nullptr; + } + + + string ToString() const { + ostringstream buffer; + + buffer << setfill('0') << setw(2) << *_dan << "."; + buffer << setfill('0') << setw(2) << *_mjesec << "."; + buffer << setfill('0') << setw(4) << *_godina << " "; + + buffer << setfill('0') << setw(2) << *_sati << ":"; + buffer << setfill('0') << setw(2) << *_minute; + + + return buffer.str(); + } + + bool operator>(const DatumVrijeme& obj) const { + if (*_godina != *obj._godina) + return *_godina > *obj._godina; + + if (*_mjesec != *obj._mjesec) + return *_mjesec > *obj._mjesec; + + if (*_dan != *obj._dan) + return *_dan > *obj._dan; + + if (*_sati != *obj._sati) + return *_sati > *obj._sati; + + return *_minute > *obj._minute; + } + + bool operator==(const DatumVrijeme& obj) const { + return (*_godina == *obj._godina && *_mjesec == *obj._mjesec && *_dan == *obj._dan && *_sati == *obj._sati && *_minute == *obj._minute); + } + +}; + + +class Posiljka { + char* _oznaka; + char* _sadrzaj; + char* _imePrezimePrimaoca; + char* _emailPrimaoca; + VrstaDostave _vrstaDostave; + int _redniBroj; + + Kolekcija _statusi; + + void Dealociraj() { + delete[] _oznaka; + delete[] _sadrzaj; + delete[] _imePrezimePrimaoca; + delete[] _emailPrimaoca; + + _oznaka = _sadrzaj = _imePrezimePrimaoca = + _emailPrimaoca = nullptr; + } + +public: + Posiljka(const char* sadrzaj, const char* imePrezimePrimaoca, const char* emailPrimaoca, VrstaDostave vrstaDostave, int redniBroj, const DatumVrijeme& vrijeme) { + _oznaka = AlocirajTekst(GenerisiOznaku(imePrezimePrimaoca, redniBroj, vrstaDostave).c_str()); + _sadrzaj = AlocirajTekst(sadrzaj); + _imePrezimePrimaoca = AlocirajTekst(imePrezimePrimaoca); + _emailPrimaoca = AlocirajTekst(emailPrimaoca); + _vrstaDostave = vrstaDostave; + _redniBroj = redniBroj; + + _statusi.Dodaj(KREIRANA, vrijeme); + } + + Posiljka(const Posiljka& obj) { + _oznaka = AlocirajTekst(obj.GetOznaka()); + _sadrzaj = AlocirajTekst(obj.GetSadrzaj()); + _imePrezimePrimaoca = AlocirajTekst(obj.GetImePrezimePrimaoca()); + _emailPrimaoca = AlocirajTekst(obj.GetEmailPrimaoca()); + _vrstaDostave = obj.GetVrstaDostave(); + _redniBroj = obj.GetRedniBroj(); + + _statusi = obj._statusi; + } + + Posiljka& operator=(const Posiljka& obj) { + if (this == &obj) return *this; + + Dealociraj(); + _oznaka = AlocirajTekst(obj.GetOznaka()); + _sadrzaj = AlocirajTekst(obj.GetSadrzaj()); + _imePrezimePrimaoca = AlocirajTekst(obj.GetImePrezimePrimaoca()); + _emailPrimaoca = AlocirajTekst(obj.GetEmailPrimaoca()); + _vrstaDostave = obj.GetVrstaDostave(); + _redniBroj = obj.GetRedniBroj(); + + _statusi = obj._statusi; + + return *this; + } + + const char* GetOznaka() const { + return _oznaka; + } + + const char* GetSadrzaj() const { + return _sadrzaj; + } + + const char* GetImePrezimePrimaoca() const { + return _imePrezimePrimaoca; + } + + const char* GetEmailPrimaoca() const { + return _emailPrimaoca; + } + + VrstaDostave GetVrstaDostave() const { + return _vrstaDostave; + } + + int GetRedniBroj() const { + return _redniBroj; + } + + Kolekcija& GetStatusi() { + return _statusi; + } + + StatusPosiljke GetTrenutniStatus() const { + return _statusi.GetElement1(_statusi.GetTrenutno() - 1); + } + + friend ostream& operator<<(ostream& COUT, const Posiljka& obj) { + // ToString vraca podatke u formatu: + // oznaka | ime i prezime | vrsta dostave | sadrzaj | trenutni status + // BH-BR-0042-AB | Amina Buric | BRZA | Dokumenti | KREIRANA + + COUT << obj.ToString(); + + return COUT; + } + + ~Posiljka() { + Dealociraj(); + } + + string ToString() const { + ostringstream buffer; + + buffer << _oznaka << " | " << _imePrezimePrimaoca << " | " << VrstaDostaveNazivi[_vrstaDostave] << " | " << _sadrzaj << " | " << StatusPosiljkeNazivi[GetTrenutniStatus()]; + + return buffer.str(); + } + + bool DodajStatus(StatusPosiljke status, const DatumVrijeme& vrijeme) { + DatumVrijeme posljednjeVrijeme = _statusi.GetElement2(_statusi.GetTrenutno() - 1); + StatusPosiljke posljednjiStatus = _statusi.GetElement1(_statusi.GetTrenutno() - 1); + if (vrijeme > posljednjeVrijeme) { + if (status == OTKAZANA) { + if (posljednjiStatus == OTKAZANA || posljednjiStatus == ISPORUCENA) { + return false; + } + _statusi.Dodaj(status, vrijeme); + return true; + } + // posto su poredani u enumu onako kako trebaju gledam jesu li tacno jedan iza drugog + else if ((int)status == (int)(posljednjiStatus + 1)) { + _statusi.Dodaj(status, vrijeme); + return true; + } + } + + return false; + } +}; + + +class DostavnaSluzba { + char* _naziv; + vector _posiljke; + +public: + DostavnaSluzba(const char* naziv = "") { + _naziv = AlocirajTekst(naziv); + } + + const char* GetNaziv() const { + return _naziv; + } + + vector& GetPosiljke() { + return _posiljke; + } + + ~DostavnaSluzba() { + delete[] _naziv; + _naziv = nullptr; + } + + + + + bool PosiljkaExists(int redniBroj) { + return any_of(_posiljke.begin(), _posiljke.end(), [&](const Posiljka &p) { + return p.GetRedniBroj() == redniBroj; + }); + } + bool PosiljkaExists(const char* oznaka) { + return any_of(_posiljke.begin(), _posiljke.end(), [&](const Posiljka& p) { + return strcmp(oznaka, p.GetOznaka()) == 0; + }); + } + + + void DodajPosiljku(const Posiljka& posiljka) { + if (PosiljkaExists(posiljka.GetRedniBroj())) { + throw exception("already exists"); + } + + if (PosiljkaExists(posiljka.GetOznaka())) { + throw exception("already exists"); + } + + _posiljke.push_back(posiljka); + + } + + Posiljka* PronadjiPosiljku(string oznaka) { + for (Posiljka& p : _posiljke) { + if (strcmp(oznaka.c_str(), p.GetOznaka()) == 0) { + return &p; + } + } + return nullptr; + } + + bool EvidentirajStatus(string oznaka, StatusPosiljke status, const DatumVrijeme& vrijeme) { + Posiljka* posiljka = PronadjiPosiljku(oznaka); + + if (!posiljka) return false; + + if (posiljka->DodajStatus(status, vrijeme)) { + + thread t([&]() { + ostringstream buffer; + + buffer << "---------------------------------------------------------------------------------" << endl << "To: " << posiljka->GetEmailPrimaoca() << endl << "From: info@brzaposta.ba" << endl; + buffer << "Subject: Promjena statusa posiljke" << endl << "Postovani " << posiljka->GetImePrezimePrimaoca() << "," << endl; + buffer << "Posiljka " << posiljka->GetOznaka() << "je promijenila status u " << StatusPosiljkeNazivi[status] << "." << endl; + buffer << "Vrijeme evidentiranja: " << vrijeme << endl << "Hvala sto koristite nase usluge.\nBrzaPosta Tim" << endl; + buffer << "---------------------------------------------------------------------------------\n"; + + cout << buffer.str(); + }); + t.join(); + return true; + } + return false; + } + vector PosiljkePoStatusu(StatusPosiljke status) { + vector posiljke; + + for (Posiljka& p : _posiljke) { + if (p.GetTrenutniStatus() == status) { + posiljke.push_back(&p); + } + } + + return posiljke; + } + + Kolekcija StatistikaPoStatusu() { + Kolekcija stats; + + for (int i = 0; i < 5; i++) { + StatusPosiljke status = (StatusPosiljke)i; + + int broj = 0; + + for (const Posiljka& p : _posiljke) { + if (p.GetTrenutniStatus() == status) + broj++; + } + + stats.Dodaj(status, broj); + } + return stats; + } +}; + +const char* GetOdgovorNaPrvoPitanje() { + cout << "Pitanje -> Pojasnite da li se svako nasljedjivanje moze " + << "posmatrati kao polimorfizam i obrnuto? Navedite konkretne " + << "primjere.\n"; + + return "Odgovor -> Ne. Nasljedjivanje je odnos bazne i izvedene klase, dok polimorfizam omogucava da se preko bazne klase pozove metoda izvedene klase. Primjer: virtualna metoda."; +} + + +const char* GetOdgovorNaDrugoPitanje() { + cout << "Pitanje -> Pojasnite razloge kojima bi se implementator " + << "klase mogao voditi pri donosenju odluke da sve metode u klasi " + << "(ne)proglasi virtualnim?\n"; + + return "Odgovor -> Metode se proglasavaju virtualnim kada zelimo polimorfno ponasanje i redefinisanje metode u izvedenim klasama. Ne moraju sve metode biti virtualne jer neke nema potrebe redefinisati."; +} + + +int main() { + cout << PORUKA_TELEFON; + cin.get(); + + cout << PORUKA_TELEFON; + cin.get(); + + cout << PORUKA_ISPIT; + cin.get(); + + system("cls"); + + cout << GetOdgovorNaPrvoPitanje() << crt; + cin.get(); + + cout << GetOdgovorNaDrugoPitanje() << crt; + cin.get(); + + + /* + Funkcija GenerisiOznaku generise oznaku posiljke u formatu: BH-VD-BBBB-IN + Potpis funkcije treba biti: + string GenerisiOznaku(const char* imePrezime, int redniBroj, + VrstaDostave vrstaDostave) + BH -> fiksna oznaka drzave, + VD -> vrsta dostave: ST (standardna), BR (brza), MD (medjunarodna), + BBBB -> redni broj posiljke popunjen nulama na slobodnim mjestima, + IN -> inicijali imena i prezimena primaoca. + Kod imena koje sadrzi vise rijeci koriste se inicijal prve i posljednje + rijeci. Redni broj mora biti u rasponu 1-9999. + Za neispravne podatke funkcija vraca "BH-XX-0000-XX". + */ + + if (GenerisiOznaku("Amina Buric", 42, BRZA) == "BH-BR-0042-AB") + cout << "Oznaka OK" << crt; + + if (GenerisiOznaku("Goran Skondric", 7, STANDARDNA) == + "BH-ST-0007-GS") + cout << "Oznaka OK" << crt; + + if (GenerisiOznaku("Ana Marija Kovac", 156, MEDJUNARODNA) == + "BH-MD-0156-AK") + cout << "Oznaka OK" << crt; + + if (GenerisiOznaku("Amina", 42, BRZA) == "BH-XX-0000-XX" && + GenerisiOznaku("Amina Buric", 0, BRZA) == "BH-XX-0000-XX" && + GenerisiOznaku("Amina Buric", 10000, BRZA) == "BH-XX-0000-XX" && + GenerisiOznaku("Amina Buric", 42, (VrstaDostave)99) == + "BH-XX-0000-XX") + cout << "Neispravni podaci za oznaku OK" << crt; + + + /* + Koristeci regex, funkcija ValidirajOznaku provjerava da li je oznaka + zapisana u prethodno definisanom formatu. Dozvoljene su iskljucivo oznake + vrsta ST, BR i MD, redni broj mora imati cetiri cifre i ne moze biti 0000, + a inicijali moraju biti zapisani velikim slovima. + Potpis funkcije treba biti: + bool ValidirajOznaku(const string& oznaka) + */ + + if (ValidirajOznaku("BH-BR-0042-AB")) + cout << "OZNAKA VALIDNA" << crt; + + if (!ValidirajOznaku("BH-EX-0042-AB") && + !ValidirajOznaku("BH-BR-042-AB") && + !ValidirajOznaku("BH-BR-0042-Ab") && + !ValidirajOznaku("BH-BR-0000-AB") && + !ValidirajOznaku("bh-BR-0042-AB")) + cout << "OZNAKA NIJE VALIDNA" << crt; + + if (ValidirajOznaku(GenerisiOznaku("Maid Ramic", 284, BRZA))) + cout << "GENERISANA OZNAKA VALIDNA" << crt; + + + Kolekcija brojevi; + + brojevi.Dodaj(10, "Deset"); + brojevi.Dodaj(20, "Dvadeset"); + brojevi.Dodaj(30, "Trideset"); + + cout << brojevi << crt; + + + /* + DodajNaPoziciju dodaje novi par na lokaciju/indeks definisanu + prvim parametrom, + pomjera postojece pokazivace udesno i vraca trenutno stanje + kolekcije (izmijenjeni tj. prosireni objekat). + U slucaju popunjene kolekcije ili neispravne lokacije potrebno je + baciti izuzetak. + */ + + Kolekcija prosireniBrojevi = + brojevi.DodajNaPoziciju(1, 15, "Petnaest"); + + cout << prosireniBrojevi << crt; + + /* + + UkloniSaPozicije uklanja par sa proslijedjene pozicije/indeksa, + preostale elemente + pomjera ulijevo i vraca uklonjeni par u obliku pair. + Za poziciju izvan opsega baca se izuzetak. + */ + pair uklonjeni = + prosireniBrojevi.UkloniSaPozicije(2); + + cout << "Uklonjeno: " << uklonjeni.first << " " + << uklonjeni.second << crt; + + cout << "Preostali elementi:" << crt + << prosireniBrojevi; + + try { + prosireniBrojevi.UkloniSaPozicije(10); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + + + try { + Kolekcija punaKolekcija; + + punaKolekcija.Dodaj(1, "Jedan"); + punaKolekcija.Dodaj(2, "Dva"); + punaKolekcija.Dodaj(3, "Tri"); + + punaKolekcija.DodajNaPoziciju(1, 4, "Cetiri"); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + + + Kolekcija kopijaBrojeva = brojevi; + + kopijaBrojeva[0] = 100; + + Kolekcija dodijeljeniBrojevi; + + dodijeljeniBrojevi = brojevi; + + dodijeljeniBrojevi[1] = 200; + + cout << "Original:" << crt << brojevi; + cout << "Kopija:" << crt << kopijaBrojeva; + cout << "Dodijeljeni objekat:" << crt << dodijeljeniBrojevi; + + + + DatumVrijeme kreirana(1, 7, 2026, 8, 0); + DatumVrijeme preuzeta(1, 7, 2026, 9, 0); + DatumVrijeme tranzit(1, 7, 2026, 10, 0); + DatumVrijeme isporucena(1, 7, 2026, 11, 0); + + + /* + ToString vraca datum i vrijeme u formatu DD.MM.GGGG HH:MM, + ukljucujuci + pocetne nule. + + */ + cout << kreirana.ToString() << crt; //01.07.2026 08:00 + + if (preuzeta > kreirana) + cout << "Vrijeme preuzimanja je nakon vremena kreiranja" << crt; + + DatumVrijeme kopijaPreuzeta(preuzeta); + + if (kopijaPreuzeta == preuzeta && !(kreirana == preuzeta)) + cout << "Provjera vremena, OK." << crt; + + /* + + Konstruktor Posiljke generise oznaku i evidentira pocetni status + KREIRANA + sa proslijedjenim vremenom kreiranja. + */ + + Posiljka dokumenti( + "Dokumenti", + "Amina Buric", + "amina@fit.ba", + BRZA, + 42, + kreirana + ); + + Posiljka knjige( + "Knjige", + "Goran Skondric", + "goran@fit.ba", + STANDARDNA, + 7, + kreirana + ); + + Posiljka oprema( + "Oprema", + "Ana Marija Kovac", + "ana@fit.ba", + MEDJUNARODNA, + 156, + kreirana + ); + + + /* + ToString vraca podatke u formatu: + oznaka | ime i prezime | vrsta dostave | sadrzaj | trenutni status + BH-BR-0042-AB | Amina Buric | BRZA | Dokumenti | KREIRANA + */ + + cout << dokumenti.ToString() << crt; + + if (dokumenti.ToString() == + "BH-BR-0042-AB | Amina Buric | BRZA | Dokumenti | KREIRANA") + cout << "Posiljka ToString OK" << crt; + + + /* + DodajStatus dodaje status samo ako je vrijeme vece od vremena + posljednjeg statusa i ako je promjena statusa dozvoljena. + Dozvoljen slijed statusa je: KREIRANA -> PREUZETA -> U_TRANZITU -> + ISPORUCENA + OTKAZANA se moze evidentirati iz bilo kojeg statusa koji nije zavrsni. + Nakon statusa ISPORUCENA ili OTKAZANA nisu dozvoljene nove promjene. + Preskakanje, ponavljanje statusa i hronoloski neispravno vrijeme vracaju + false, bez izmjene kolekcije statusa. + */ + + if (dokumenti.DodajStatus(PREUZETA, preuzeta)) + cout << "Status PREUZETA dodan" << crt; + + if (dokumenti.DodajStatus(U_TRANZITU, tranzit)) + cout << "Status U TRANZITU dodan" << crt; + + if (dokumenti.DodajStatus(ISPORUCENA, isporucena)) + cout << "Status ISPORUCENA dodan" << crt; + + if (!dokumenti.DodajStatus(OTKAZANA, isporucena)) + cout << "Promjena zavrsnog statusa nije dozvoljena" << crt; + + if (!knjige.DodajStatus(U_TRANZITU, preuzeta)) + cout << "Preskakanje statusa nije dozvoljeno" << crt; + + if (oprema.DodajStatus(OTKAZANA, preuzeta)) + cout << "Posiljka otkazana" << crt; + + + Posiljka kopijaDokumenata = dokumenti; + + cout << kopijaDokumenata << crt; + + + DostavnaSluzba brzaPosta("Brza posta"); + + + /* + DodajPosiljku dodaje posiljku u dostavnu sluzbu. Nije dozvoljeno dodati + dvije posiljke sa istim rednim brojem ili istom oznakom. U slucaju + duplikata metoda baca izuzetak. + */ + + brzaPosta.DodajPosiljku(knjige); + brzaPosta.DodajPosiljku(oprema); + + try { + brzaPosta.DodajPosiljku(knjige); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + + + /* + PronadjiPosiljku vraca pokazivac na posiljku sa proslijedjenom oznakom. + Ako posiljka nije pronadjena, metoda vraca nullptr. + */ + + string oznakaKnjige = knjige.GetOznaka(); + + Posiljka* pronadjena = + brzaPosta.PronadjiPosiljku(oznakaKnjige); + + if (pronadjena != nullptr) + cout << "Pronadjena posiljka: " + << pronadjena->GetOznaka() << crt; + + if (brzaPosta.PronadjiPosiljku("BH-ST-9999-XX") == nullptr) + cout << "Nepostojeca posiljka nije pronadjena" << crt; + + + /* + EvidentirajStatus pronalazi posiljku na osnovu oznake i pokusava + dodati + novi status koristeci pravila metode DodajStatus. + Nakon svakog uspjesno evidentiranog statusa potrebno je u zasebnom + threadu + poslati obavijest primaocu. Obavijest se ne salje ako posiljka ne + postoji ili status nije dodan, te u tim slucajevima metoda vraca + false. + Primjer sadrzaja obavijesti: + ------------------------------------------------------------------ + --------------- + To: goran@fit.ba + From: info@brzaposta.ba + Subject: Promjena statusa posiljke + Postovani Goran Skondric, + Posiljka BH-ST-0007-GS je promijenila status u PREUZETA. + Vrijeme evidentiranja: 01.07.2026 09:00 + Hvala sto koristite nase usluge. + BrzaPosta Tim + ------------------------------------------------------------------ + --------------- + */ + + if (brzaPosta.EvidentirajStatus( + oznakaKnjige, + PREUZETA, + preuzeta)) + cout << "Status evidentiran i obavijest poslana" << crt; + + if (!brzaPosta.EvidentirajStatus( + oznakaKnjige, + ISPORUCENA, + isporucena)) + cout << "Obavijest nije poslana za neispravnu promjenu " + << "statusa" << crt; + + if (!brzaPosta.EvidentirajStatus( + "NEPOSTOJECA", + PREUZETA, + preuzeta)) + cout << "Obavijest nije poslana za nepostojecu posiljku" + << crt; + + + /* + PosiljkePoStatusu vraca vector pokazivaca na sve posiljke ciji trenutni + status odgovara proslijedjenom statusu. + + */ + vector preuzetePosiljke = + brzaPosta.PosiljkePoStatusu(PREUZETA); + + for (auto posiljka : preuzetePosiljke) + cout << posiljka->GetOznaka() << " -> " + << StatusPosiljkeNazivi[ + (int)posiljka->GetTrenutniStatus() + ] + << crt; + + + /* + StatistikaPoStatusu vraca kolekciju koja za svaki status, + redoslijedom + definisanim enumom StatusPosiljke, sadrzi status i broj posiljki koje se + trenutno nalaze u tom statusu. U rezultat se dodaje svih pet statusa, + ukljucujuci i one za koje je broj posiljki jednak nuli. + */ + + Kolekcija statistika = + brzaPosta.StatistikaPoStatusu(); + + for (int i = 0; i < statistika.GetTrenutno(); i++) + cout << StatusPosiljkeNazivi[ + (int)statistika.GetElement1(i) + ] + << " -> " + << statistika.GetElement2(i) + << crt; + + + DostavnaSluzba kopijaSluzbe = brzaPosta; + + cout << kopijaSluzbe.GetNaziv() << " ima " + << kopijaSluzbe.GetPosiljke().size() + << " posiljki" << crt; + + cin.get(); + + return 0; +} diff --git a/Ispiti/2026-07-09/PR2_2026_07_09_G2_Postavka.cpp b/Ispiti/2026-07-09/PR2_2026_07_09_G2_Postavka.cpp new file mode 100644 index 0000000..6b8e61d --- /dev/null +++ b/Ispiti/2026-07-09/PR2_2026_07_09_G2_Postavka.cpp @@ -0,0 +1,547 @@ +#include +using namespace std; + +string crt = "\n-------------------------------------------------------------------------------- - \n"; + +string PORUKA_TELEFON = crt + + "TELEFONE ISKLJUCITE I ODLOZITE U TORBU, DZEP ILI DRUGU LOKACIJU VAN DOHVATA.\n" + "CESTO SE NA TELEFONIMA (PRO)NALAZE PROGRAMSKI KODOVI KOJI MOGU BITI ISKORISTENI ZA\n" + "RJESAVANJE ISPITNOG ZADATKA, STO CE, U SLUCAJU PRONALASKA, BITI SANKCIONISANO.\n\n" + "SVI KOD KOJIH BUDE PRONADJEN TELEFON ILI NEKI DRUGI UREDJAJ KOJI MOZE SADRZAVATI\n" + "MATERIJAL ILI RJESENJA ISPITNIH ZADATAKA CE BITI UDALJENI SA ISPITA I BIT CE POKRENUT\n" + "POSTUPAK PROTIV NJIH" + crt; + +string PORUKA_ISPIT = crt + + "0. PROVJERITE DA LI ZADACI PRIPADAJU VASOJ GRUPI (G1/G2)\n" + "1. SVE KLASE SA DINAMICKOM ALOKACIJOM MORAJU IMATI ISPRAVAN DESTRUKTOR\n" + "2. IZOSTAVLJANJE DESTRUKTORA ILI NJEGOVIH DIJELOVA BIT CE OZNACENO KAO TM\n" + "3. ATRIBUTI, METODE I PARAMETRI MORAJU BITI IDENTICNI ONIMA U TESTNOJ MAIN FUNKCIJI, \n" + " OSIM AKO POSTOJI JASNO OPISAN RAZLOG ZA MODIFIKACIJU\n" + "4. IZUZETKE BACAJTE SAMO TAMO GDJE JE IZRICITO NAGLASENO\n" + "5. SVE METODE KOJE SE POZIVAJU U MAIN-U MORAJU POSTOJATI.\n" + " AKO NEMATE ZELJENU IMPLEMENTACIJU, OSTAVITE PRAZNO TIJELO ILI VRATITE DEFAULT VRIJEDNOST\n" + "6. U MAIN FUNKCIJI MOZETE DODAVATI TESTNE PODATKE I POZIVE PO VLASTITOM IZBORU\n" + "7. TESTIRAJTE PROGRAM U OBA MODA (F5 i Ctrl+F5)" + crt; + +char* AlocirajTekst(const char* tekst) { + if (tekst == nullptr) return nullptr; + size_t velicina = strlen(tekst) + 1; + char* noviTekst = new char[velicina]; + strcpy_s(noviTekst, velicina, tekst); + return noviTekst; +} + +enum StatusZahtjeva { ZAPRIMLJEN, DIJAGNOSTIKA, POPRAVKA, ZAVRSEN }; + +const char* StatusZahtjevaNazivi[] = { + "ZAPRIMLJEN", "DIJAGNOSTIKA", "POPRAVKA", "ZAVRSEN" +}; + +template +class Kolekcija { + T1* _elementi1; + T2* _elementi2; + int _trenutno; + +public: + Kolekcija() : _trenutno(0) { + _elementi1 = new T1[max]; + _elementi2 = new T2[max]; + } + + T1& GetElement1(int indeks) { + return _elementi1[indeks]; + } + + const T1& GetElement1(int indeks) const { + return _elementi1[indeks]; + } + + T2& GetElement2(int indeks) { + return _elementi2[indeks]; + } + + const T2& GetElement2(int indeks) const { + return _elementi2[indeks]; + } + + int GetTrenutno() const { return _trenutno; } + + friend ostream& operator<<(ostream& COUT, const Kolekcija& obj) { + for (int i = 0; i < obj.GetTrenutno(); i++) + COUT << obj.GetElement1(i) << " " << obj.GetElement2(i) << endl; + return COUT; + } + + ~Kolekcija() { + delete[] _elementi1; + delete[] _elementi2; + _elementi1 = nullptr; + _elementi2 = nullptr; + _trenutno = 0; + } +}; + +class DatumVrijeme { + int* _dan, *_mjesec, *_godina, *_sati, *_minute; + +public: + DatumVrijeme(int dan = 1, int mjesec = 1, int godina = 2000, + int sati = 0, int minute = 0) { + _dan = new int(dan); + _mjesec = new int(mjesec); + _godina = new int(godina); + _sati = new int(sati); + _minute = new int(minute); + } + + int GetGodina() const { return *_godina; } + + friend ostream& operator<<(ostream& COUT, const DatumVrijeme& obj) { + // ToString vraca datum i vrijeme u formatu DD.MM.GGGG HH:MM + COUT << obj.ToString(); + return COUT; + } + + ~DatumVrijeme() { + delete _dan; + delete _mjesec; + delete _godina; + delete _sati; + delete _minute; + _dan = _mjesec = _godina = _sati = _minute = nullptr; + } +}; + +class Intervencija { + string _opis; + string _tehnicar; + double _cijena; + int _trajanjeMinuta; + +public: + const string& GetOpis() const { return _opis; } + const string& GetTehnicar() const { return _tehnicar; } + double GetCijena() const { return _cijena; } + int GetTrajanjeMinuta() const { return _trajanjeMinuta; } + + friend ostream& operator<<(ostream& COUT, const Intervencija& obj) { + COUT << obj.ToString(); + return COUT; + } + + /* + ToString vraca podatke u formatu : + opis | tehnicar | cijena KM | trajanje min + Zamjena diska | Haris Hadzic | 85.50 KM | 45 min + */ +}; + +class Klijent { + string _imePrezime; + string _email; + string _telefon; + +public: + const string& GetImePrezime() const { return _imePrezime; } + const string& GetEmail() const { return _email; } + const string& GetTelefon() const { return _telefon; } + + friend ostream& operator<<(ostream& COUT, const Klijent& obj) { + COUT << obj.GetImePrezime() << " | " << obj.GetEmail() + << " | " << obj.GetTelefon(); + return COUT; + } +}; + +class ServisniZahtjev { + char* _oznaka; + char* _uredjaj; + char* _opisKvara; + int _redniBroj; + Klijent _klijent; + Kolekcija _statusi; + vector _intervencije; + +public: + const char* GetOznaka() const { return _oznaka; } + const char* GetUredjaj() const { return _uredjaj; } + const char* GetOpisKvara() const { return _opisKvara; } + int GetRedniBroj() const { return _redniBroj; } + + Klijent& GetKlijent() { return _klijent; } + const Klijent& GetKlijent() const { return _klijent; } + + Kolekcija& GetStatusi() { + return _statusi; + } + + const Kolekcija& GetStatusi() const { + return _statusi; + } + + vector& GetIntervencije() { return _intervencije; } + + const vector& GetIntervencije() const { + return _intervencije; + } + + StatusZahtjeva GetTrenutniStatus() const { + return _statusi.GetElement1(_statusi.GetTrenutno() - 1); + } + + friend ostream& operator<<(ostream& COUT, const ServisniZahtjev& obj) { + // ToString vraca: + // oznaka | ime i prezime klijenta | uredjaj | trenutni status + COUT << obj.ToString(); + return COUT; + } + + ~ServisniZahtjev() { + delete[] _oznaka; + delete[] _uredjaj; + delete[] _opisKvara; + _oznaka = _uredjaj = _opisKvara = nullptr; + } +}; + +class Servis { + char* _naziv; + vector _zahtjevi; + +public: + Servis(const char* naziv = "") { + _naziv = AlocirajTekst(naziv); + } + + const char* GetNaziv() const { return _naziv; } + + vector& GetZahtjevi() { return _zahtjevi; } + + const vector& GetZahtjevi() const { + return _zahtjevi; + } + + ~Servis() { + delete[] _naziv; + _naziv = nullptr; + } +}; + +const char* GetOdgovorNaPrvoPitanje() { + cout << "Pitanje -> Pojasnite zbog cega se operator<< implementira " + "kao globalna a ne funkcija clanica, te na koji nacin se implementiraju " + "prefiksalni i postfiksni oblik operatora inkrementiranja?\n"; + return "Odgovor -> OVDJE UNESITE VAS ODGOVOR"; +} + +const char* GetOdgovorNaDrugoPitanje() { + cout << "Pitanje -> Pojasnite nacin na koji biste, koristeci " + "obradjene klase i metode, mogli saznati velicinu nekog tekstualnog fajla.\n"; + return "Odgovor -> OVDJE UNESITE VAS ODGOVOR"; +} + +int main() { + cout << PORUKA_TELEFON; + cin.get(); + + cout << PORUKA_TELEFON; + cin.get(); + + cout << PORUKA_ISPIT; + cin.get(); + + system("cls"); + + cout << GetOdgovorNaPrvoPitanje() << crt; + cin.get(); + + cout << GetOdgovorNaDrugoPitanje() << crt; + cin.get(); + + /* + Funkcija GenerisiOznaku generise oznaku servisnog zahtjeva u formatu: + SRV-BBB/IN-GGGG + + Potpis funkcije treba biti: + string GenerisiOznaku(const char* imePrezime, int redniBroj, int godina) + + SRV -> fiksni prefiks + BBB -> redni broj zahtjeva popunjen nulama na slobodnim mjestima + IN -> inicijali imena i prezimena klijenta + GGGG -> godina zaprimanja zahtjeva. + + Kod imena koje sadrzi vise rijeci koriste se inicijal prve i posljednje + rijeci. + + Redni broj mora biti u rasponu 1-999, a godina 2000-2099. + Za neispravne podatke funkcija vraca "SRV-000/XX-0000". + */ + + if (GenerisiOznaku("Amina Buric", 42, 2026) == "SRV-042/AB-2026") + cout << "Oznaka OK" << crt; + + if (GenerisiOznaku("Goran Skondric", 7, 2026) == "SRV-007/GS 2026") + cout << "Oznaka OK" << crt; + + if (GenerisiOznaku("Ana Marija Kovac", 156, 2027) == + "SRV-156/AK-2027") + cout << "Oznaka OK" << crt; + + if (GenerisiOznaku("Amina", 42, 2026) == "SRV-000/XX-0000" && + GenerisiOznaku("Amina Buric", 0, 2026) == "SRV-000/XX-0000" && + GenerisiOznaku("Amina Buric", 1000, 2026) == "SRV-000/XX-0000" && + GenerisiOznaku("Amina Buric", 42, 1999) == "SRV-000/XX-0000") + cout << "Neispravni podaci za oznaku OK" << crt; + + /* + Koristeci regex, funkcija ValidirajOznaku provjerava prethodno + definisani format. Prefiks mora biti SRV, redni broj mora imati + tri cifre i ne moze biti 000, inicijali moraju biti velika slova, + a godina je 2000-2099. + + Potpis funkcije treba biti: + bool ValidirajOznaku(const string& oznaka) + */ + + if (ValidirajOznaku("SRV-042/AB-2026")) + cout << "OZNAKA VALIDNA" << crt; + + if (!ValidirajOznaku("SRV/042-AB-2026") && + !ValidirajOznaku("SRV-42/AB-2026") && + !ValidirajOznaku("SRV-042/Ab-2026") && + !ValidirajOznaku("SRV-000/AB-2026") && + !ValidirajOznaku("2026-SRV-042/AB")) + cout << "OZNAKA NIJE VALIDNA" << crt; + + Kolekcija brojevi; + brojevi.Dodaj(10, "Deset"); + brojevi.Dodaj(20, "Dvadeset"); + brojevi.Dodaj(10, "Deset"); + brojevi.Dodaj(30, "Trideset"); + brojevi.Dodaj(20, "Dvadeset"); + + cout << brojevi << crt; + + /* + UkloniDuplikate vraca novu kolekciju u kojoj je zadrzano samo prvo + pojavljivanje svakog para. Par predstavlja duplikat iskljucivo ako su + jednaki i prvi i drugi element. Originalna kolekcija ostaje nepromijenjena. + */ + + Kolekcija bezDuplikata = brojevi.UkloniDuplikate(); + + cout << "Bez duplikata:" << crt << bezDuplikata; + cout << "Original:" << crt << brojevi; + + try { + Kolekcija puna; + puna.Dodaj(1, "Jedan"); + puna.Dodaj(2, "Dva"); + puna.Dodaj(3, "Tri"); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + + Kolekcija kopijaBrojeva = brojevi; + kopijaBrojeva[0] = 100; + + Kolekcija dodijeljeniBrojevi; + dodijeljeniBrojevi = brojevi; + dodijeljeniBrojevi.GetElement2(0) = "Izmijenjeno"; + + cout << "Original:" << crt << brojevi; + cout << "Kopija:" << crt << kopijaBrojeva; + cout << "Dodijeljeni objekat:" << crt << dodijeljeniBrojevi; + + DatumVrijeme zaprimljen(9, 7, 2026, 8, 0); + DatumVrijeme dijagnostika(9, 7, 2026, 9, 0); + DatumVrijeme popravka(9, 7, 2026, 10, 0); + DatumVrijeme zavrsen(9, 7, 2026, 11, 0); + + /* + ToString vraca datum i vrijeme u formatu DD.MM.GGGG HH:MM, + ukljucujuci pocetne nule. + */ + + cout << zaprimljen.ToString() << crt; // 09.07.2026 08:00 + + if (dijagnostika > zaprimljen) + cout << "Vrijeme dijagnostike je nakon zaprimanja" << crt; + + DatumVrijeme kopijaDatuma(dijagnostika); + + if (kopijaDatuma == dijagnostika && !(zaprimljen == dijagnostika)) + cout << "Provjera vremena, OK." << crt; + + Klijent amina("Amina Buric", "amina@fit.ba", "061-111-222"); + Klijent goran("Goran Skondric", "goran@fit.ba", "062-222-333"); + Klijent kopijaKlijenta = amina; + + cout << kopijaKlijenta << crt; + + /* + Intervencija sadrzi opis, ime tehnicara, cijenu i trajanje u minutama. + */ + + Intervencija pregled("Dijagnostika uredjaja", "Haris Hadzic", 20, 30); + Intervencija zamjenaDiska("Zamjena diska", "Haris Hadzic", 85.5, 45); + Intervencija instalacija("Instalacija sistema", "Maja Majic", 35, 60); + + /* + ToString vraca podatke u formatu: + opis | tehnicar | cijena KM | trajanje min + Zamjena diska | Haris Hadzic | 85.50 KM | 45 min + */ + + cout << zamjenaDiska.ToString() << crt; + + /* + Konstruktor ServisnogZahtjeva generise oznaku na osnovu klijenta, + rednog broja i godine zaprimanja, te evidentira pocetni status + ZAPRIMLJEN sa proslijedjenim vremenom. + */ + + ServisniZahtjev laptop("Laptop", "Ne pokrece se", amina, 42, zaprimljen); + ServisniZahtjev telefon("Telefon", "Razbijen ekran", goran, 7, zaprimljen); + + /* + ToString vraca podatke u formatu: + oznaka | ime i prezime klijenta | uredjaj | trenutni status + + SRV-042/AB-2026 | Amina Buric | Laptop | ZAPRIMLJEN + */ + + cout << laptop.ToString() << crt; + + if (laptop.ToString() == + "SRV-042/AB-2026 | Amina Buric | Laptop | ZAPRIMLJEN") + cout << "ServisniZahtjev ToString OK" << crt; + + /* + DodajStatus dodaje status samo ako je vrijeme vece od vremena posljednjeg + statusa i ako status predstavlja neposredno sljedecu fazu. + + Dozvoljen slijed je: + ZAPRIMLJEN -> DIJAGNOSTIKA -> POPRAVKA -> ZAVRSEN + + Preskakanje ili ponavljanje statusa nije dozvoljeno. Nakon statusa ZAVRSEN + nisu dozvoljene nove promjene. Neuspjesan pokusaj vraca false bez izmjene + kolekcije statusa. + */ + + if (!laptop.DodajStatus(POPRAVKA, dijagnostika)) + cout << "Preskakanje statusa nije dozvoljeno" << crt; + + if (laptop.DodajStatus(DIJAGNOSTIKA, dijagnostika)) + cout << "Status DIJAGNOSTIKA dodan" << crt; + + if (!laptop.DodajStatus(DIJAGNOSTIKA, popravka)) + cout << "Ponavljanje statusa nije dozvoljeno" << crt; + + /* + DodajIntervenciju dodaje intervenciju samo dok je zahtjev u statusu + DIJAGNOSTIKA ili POPRAVKA, uz cijenu i trajanje vece od nule. + + Metoda vraca true ako je intervencija dodana, u suprotnom false. + UkupnaCijena vraca zbir cijena svih intervencija, a UkupnoTrajanje + zbir njihovih trajanja u minutama. + */ + + if (laptop.DodajIntervenciju(pregled)) + cout << "Intervencija dodana" << crt; + + if (laptop.DodajStatus(POPRAVKA, popravka)) + cout << "Status POPRAVKA dodan" << crt; + + laptop.DodajIntervenciju(zamjenaDiska); + laptop.DodajIntervenciju(instalacija); + + cout << "Ukupna cijena: " << laptop.UkupnaCijena() << " KM" << crt; + cout << "Ukupno trajanje: " << laptop.UkupnoTrajanje() << " min" << crt; + + ServisniZahtjev kopijaLaptopa = laptop; + cout << kopijaLaptopa << crt; + + Servis fitServis("FIT Servis"); + + /* + DodajZahtjev dodaje zahtjev u servis. Nije dozvoljeno dodati dva zahtjeva + sa istim rednim brojem ili istom oznakom. U slucaju duplikata metoda baca + izuzetak. + */ + + fitServis.DodajZahtjev(laptop); + fitServis.DodajZahtjev(telefon); + + try { + fitServis.DodajZahtjev(telefon); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + + /* + PronadjiZahtjev vraca pokazivac na zahtjev sa proslijedjenom oznakom. + Ako zahtjev nije pronadjen, metoda vraca nullptr. + */ + + string oznakaLaptopa = laptop.GetOznaka(); + ServisniZahtjev* pronadjen = fitServis.PronadjiZahtjev(oznakaLaptopa); + + if (pronadjen != nullptr) + cout << "Pronadjen zahtjev: " << pronadjen->GetOznaka() << crt; + + if (fitServis.PronadjiZahtjev("SRV-999/XX-2026") == nullptr) + cout << "Zahtjev nije pronadjen" << crt; + + /* + EvidentirajStatus pronalazi zahtjev i pokusava dodati status koristeci + pravila metode DodajStatus. + + Racun se salje u zasebnom threadu iskljucivo nakon uspjesnog evidentiranja + statusa ZAVRSEN. Za ostale statuse se ne salju obavijesti. + + Ako zahtjev ne postoji ili status nije dodan, metoda vraca false. + */ + + if (fitServis.EvidentirajStatus(oznakaLaptopa, ZAVRSEN, zavrsen)) + cout << "Zahtjev zavrsen i racun poslan" << crt; + + if (!fitServis.EvidentirajStatus( + oznakaLaptopa, ZAVRSEN, DatumVrijeme(9, 7, 2026, 12, 0))) + cout << "Ponavljanje zavrsnog statusa nije dozvoljeno" << crt; + + if (!fitServis.EvidentirajStatus( + "NEPOSTOJECI", DIJAGNOSTIKA, dijagnostika)) + cout << "Status nije evidentiran za nepostojeci zahtjev" << crt; + + /* + IzdvojiNezavrsene vraca vector pokazivaca na sve zahtjeve ciji trenutni + status nije ZAVRSEN. + */ + + vector nezavrseni = fitServis.IzdvojiNezavrsene(); + + for (auto zahtjev : nezavrseni) + cout << zahtjev->GetOznaka() << " -> " + << StatusZahtjevaNazivi[(int)zahtjev->GetTrenutniStatus()] << crt; + + /* + IzracunajPrihod vraca zbir cijena svih intervencija evidentiranih + zahtjevima koji imaju status ZAVRSEN. Intervencije na nezavrsenim + zahtjevima ne ulaze u prihod. + */ + + cout << "Ostvareni prihod: " << fitServis.IzracunajPrihod() + << " KM" << crt; + + Servis kopijaServisa = fitServis; + + cout << kopijaServisa.GetNaziv() << " ima " + << kopijaServisa.GetZahtjevi().size() << " zahtjeva" << crt; + + cin.get(); + return 0; +} diff --git "a/Ispiti/2026-07-09/PR2_2026_07_09_G2_Rje\305\241enje.cpp" "b/Ispiti/2026-07-09/PR2_2026_07_09_G2_Rje\305\241enje.cpp" new file mode 100644 index 0000000..638dcbd --- /dev/null +++ "b/Ispiti/2026-07-09/PR2_2026_07_09_G2_Rje\305\241enje.cpp" @@ -0,0 +1,856 @@ +#include +#include +#include +#include +#include +#include + + +using namespace std; + +string crt = "\n-------------------------------------------------------------------------------- - \n"; +string PORUKA_TELEFON = crt + "TELEFONE ISKLJUCITE I ODLOZITE U TORBU, DZEP ILI DRUGU LOKACIJU VAN DOHVATA.\n" +"CESTO SE NA TELEFONIMA (PRO)NALAZE PROGRAMSKI KODOVI KOJI MOGU BITI ISKORISTENI ZA\n" +"RJESAVANJE ISPITNOG ZADATKA, STO CE, U SLUCAJU PRONALASKA, BITI SANKCIONISANO.\n\n" +"SVI KOD KOJIH BUDE PRONADJEN TELEFON ILI NEKI DRUGI UREDJAJ KOJI MOZE SADRZAVATI\n" +"MATERIJAL ILI RJESENJA ISPITNIH ZADATAKA CE BITI UDALJENI SA ISPITA I BIT CE POKRENUT\n" +"POSTUPAK PROTIV NJIH" + crt; + +string PORUKA_ISPIT = crt + +"0. PROVJERITE DA LI ZADACI PRIPADAJU VASOJ GRUPI (G1/G2)\n" +"1. SVE KLASE SA DINAMICKOM ALOKACIJOM MORAJU IMATI ISPRAVAN DESTRUKTOR\n" +"2. IZOSTAVLJANJE DESTRUKTORA ILI NJEGOVIH DIJELOVA BIT CE OZNACENO KAO TM\n" +"3. ATRIBUTI, METODE I PARAMETRI MORAJU BITI IDENTICNI ONIMA U TESTNOJ MAIN FUNKCIJI, \n" +" OSIM AKO POSTOJI JASNO OPISAN RAZLOG ZA MODIFIKACIJU\n" +"4. IZUZETKE BACAJTE SAMO TAMO GDJE JE IZRICITO NAGLASENO\n" +"5. SVE METODE KOJE SE POZIVAJU U MAIN-U MORAJU POSTOJATI.\n" +" AKO NEMATE ZELJENU IMPLEMENTACIJU, OSTAVITE PRAZNO TIJELO ILI VRATITE DEFAULT VRIJEDNOST\n" +"6. U MAIN FUNKCIJI MOZETE DODAVATI TESTNE PODATKE I POZIVE PO VLASTITOM IZBORU\n" +"7. TESTIRAJTE PROGRAM U OBA MODA (F5 i Ctrl+F5)" + crt; + + +char* AlocirajTekst(const char* tekst) { + if (tekst == nullptr) return nullptr; + size_t velicina = strlen(tekst) + 1; + char* noviTekst = new char[velicina]; + strcpy_s(noviTekst, velicina, tekst); + return noviTekst; +} + +enum StatusZahtjeva { ZAPRIMLJEN, DIJAGNOSTIKA, POPRAVKA, ZAVRSEN }; + +const char* StatusZahtjevaNazivi[] = { + "ZAPRIMLJEN", "DIJAGNOSTIKA", "POPRAVKA", "ZAVRSEN" +}; + + +string GenerisiOznaku(const char* imePrezime, int redniBroj, int godina) { + if (redniBroj < 1 || redniBroj > 999) { + return "SRV-000/XX-0000"; + } + + if (godina < 2000 || godina > 2099) { + return "SRV-000/XX-0000"; + } + + ostringstream buffer; + + string s_imePrezime = imePrezime; + + size_t lastSpace = s_imePrezime.find_last_of(' '); + + if (lastSpace == string::npos || lastSpace == s_imePrezime.size() - 1) { + return "SRV-000/XX-0000"; + } + + buffer << "SRV-" << setfill('0') << setw(3) << redniBroj << "/" << imePrezime[0] << imePrezime[lastSpace + 1] << "-" << godina; + + return buffer.str(); +} + +/* +Koristeci regex, funkcija ValidirajOznaku provjerava prethodno +definisani + format. Prefiks mora biti SRV, redni broj mora imati tri cifre i +ne moze + biti 000, inicijali moraju biti velika slova, a godina je 2000- +2099. + Potpis funkcije treba biti: + bool ValidirajOznaku(const string& oznaka) + */ +bool ValidirajOznaku(const string& oznaka) { + return regex_match(oznaka, regex("SRV-(?!000)[0-9]{3}/[A-Z]{2}-20([0-9]{2})")); +} + +template +class Kolekcija { + T1* _elementi1; + T2* _elementi2; + int _trenutno; +public: + Kolekcija() : _trenutno(0) { + _elementi1 = new T1[max]; + _elementi2 = new T2[max]; + } + + Kolekcija(const Kolekcija& other) : _trenutno(other._trenutno) { + _elementi1 = new T1[max]; + _elementi2 = new T2[max]; + + for (int i = 0; i < _trenutno; i++) { + _elementi1[i] = other._elementi1[i]; + _elementi2[i] = other._elementi2[i]; + } + } + + Kolekcija& operator=(const Kolekcija& other) { + if (this == &other) return *this; + _trenutno = other._trenutno; + + delete[] _elementi1; + delete[] _elementi2; + _elementi1 = nullptr; + _elementi2 = nullptr; + + _elementi1 = new T1[max]; + _elementi2 = new T2[max]; + + for (int i = 0; i < _trenutno; i++) { + _elementi1[i] = other._elementi1[i]; + _elementi2[i] = other._elementi2[i]; + } + return *this; + } + + T1& operator [] (int idx) { + return _elementi1[idx]; + } + + int GetTrenutno() const { return _trenutno; } + + const T1& GetElement1(int indeks) const { + return _elementi1[indeks]; + } + + const T2& GetElement2(int indeks) const { + return _elementi2[indeks]; + } + + T2& GetElement2(int index) { + return _elementi2[index]; + } + + friend ostream& operator<<(ostream& COUT, const Kolekcija& obj) { + for (int i = 0; i < obj.GetTrenutno(); i++) + COUT << obj.GetElement1(i) << " " << obj.GetElement2(i) << + endl; + return COUT; + } + ~Kolekcija() { + delete[] _elementi1; + delete[] _elementi2; + _elementi1 = nullptr; + _elementi2 = nullptr; + _trenutno = 0; + } + + void Dodaj(T1 el1, T2 el2) { + if (_trenutno >= max) { + throw exception("collection full"); + }; + _elementi1[_trenutno] = el1; + _elementi2[_trenutno] = el2; + + _trenutno++; + } + + Kolekcija UkloniDuplikate() { + Kolekcija nova; + + for (int i = 0; i < _trenutno; i++) { + int postoji = false; + for (int j = 0; i < _trenutno; j++) { + if (_elementi1[i] == nova.GetElement1(j) && _elementi2[i] == nova.GetElement2(j)) { + postoji = true; + break; + } + } + + if (!postoji) { + nova.Dodaj(_elementi1[i], _elementi2[i]); + } + } + + return nova; + } + +}; + + + + + +class DatumVrijeme { + int* _dan, * _mjesec, * _godina, * _sati, * _minute; +public: + DatumVrijeme(int dan = 1, int mjesec = 1, int godina = 2000, + int sati = 0, int minute = 0) { + _dan = new int(dan); + _mjesec = new int(mjesec); + _godina = new int(godina); + _sati = new int(sati); + _minute = new int(minute); + } + + DatumVrijeme(const DatumVrijeme& other) { + _dan = new int(*other._dan); + _mjesec = new int(*other._mjesec); + _godina = new int(*other._godina); + _sati = new int(*other._sati); + _minute = new int(*other._minute); + } + DatumVrijeme& operator=(const DatumVrijeme& other) { + if (this == &other) return *this; + delete _dan; + delete _mjesec; + delete _godina; + delete _sati; + delete _minute; + _dan = _mjesec = _godina = _sati = _minute = nullptr; + + _dan = new int(*other._dan); + _mjesec = new int(*other._mjesec); + _godina = new int(*other._godina); + _sati = new int(*other._sati); + _minute = new int(*other._minute); + return *this; + } + int GetGodina() const { return *_godina; } + friend ostream& operator<<(ostream& COUT, const DatumVrijeme& obj) + { + // ToString vraca datum i vrijeme u formatu DD.MM.GGGG HH:MM + COUT << obj.ToString(); + return COUT; + } + + string ToString() const { + ostringstream buffer; + + buffer << setfill('0') << setw(2) << *_dan << "."; + buffer << setfill('0') << setw(2) << *_mjesec << "."; + buffer << setfill('0') << setw(4) << *_godina << " "; + buffer << setfill('0') << setw(2) << *_sati << ":"; + buffer << setfill('0') << setw(2) << *_minute << endl; + + + return buffer.str(); + } + + ~DatumVrijeme() { + delete _dan; + delete _mjesec; + delete _godina; + delete _sati; + delete _minute; + _dan = _mjesec = _godina = _sati = _minute = nullptr; + } + + bool operator > (const DatumVrijeme& other) const { + if (*_godina != *other._godina) return *_godina > *other._godina; + if (*_mjesec != *other._mjesec) return *_mjesec > *other._mjesec; + if (*_dan != *other._dan) return *_dan > *other._dan; + + if (*_sati != *other._sati) return *_sati > *other._sati; + + + return *_minute > *other._minute; + } + + bool operator == (const DatumVrijeme& other) const { + return *_godina == *other._godina && + *_mjesec == *other._mjesec && + *_dan == *other._dan && + *_sati == *other._sati && + *_minute == *other._minute; + } + +}; + +class Intervencija { + string _opis; + string _tehnicar; + double _cijena; + int _trajanjeMinuta; +public: + const string& GetOpis() const { return _opis; } + const string& GetTehnicar() const { return _tehnicar; } + double GetCijena() const { return _cijena; } + int GetTrajanjeMinuta() const { return _trajanjeMinuta; } + friend ostream& operator<<(ostream& COUT, const Intervencija& obj) + { + /* + ToString vraca podatke u formatu : + opis | tehnicar | cijena KM | trajanje min + Zamjena diska | Haris Hadzic | 85.50 KM | 45 min + */ + COUT << obj.ToString(); + return COUT; + } + Intervencija(const char* opis, const char* tehnicar, double cijena, int trajanje) : _opis(opis), _tehnicar(tehnicar), _cijena(cijena), _trajanjeMinuta(trajanje) {} + + string ToString() const { + ostringstream buffer; + + buffer << GetOpis() << " | " << GetTehnicar() << " | " << GetCijena() << " | " << GetTrajanjeMinuta() << endl; + + return buffer.str(); + } + +}; + + + +class Klijent { + string _imePrezime; + string _email; + string _telefon; +public: + Klijent(const char* imePrezime, const char* email, const char* telefon) { + _imePrezime = imePrezime; + _email = email; + _telefon = telefon; + } + // ovdje inace nisu potrebni copy constructori, oni se inace prave kada imas pointer u klasi, npr da je bilo char* _imePrezime, ovako ga obicno ne moras pravit jer nema brige hocel se desit shallow copy + Klijent(const Klijent& other) { + _imePrezime = other.GetImePrezime(); + _email = other.GetEmail(); + _telefon = other.GetTelefon(); + } + + Klijent& operator=(const Klijent& other) { + if (this == &other) return *this; + _imePrezime = other.GetImePrezime(); + _email = other.GetEmail(); + _telefon = other.GetTelefon(); + return *this; + } + const string& GetImePrezime() const { return _imePrezime; } + const string& GetEmail() const { return _email; } + const string& GetTelefon() const { return _telefon; } + friend ostream& operator<<(ostream& COUT, const Klijent& obj) { + COUT << obj.GetImePrezime() << " | " << obj.GetEmail() + << " | " << obj.GetTelefon(); + return COUT; + } +}; + + + +class ServisniZahtjev { + char* _oznaka; + char* _uredjaj; + char* _opisKvara; + int _redniBroj; + Klijent _klijent; + Kolekcija _statusi; + vector _intervencije; +public: + const char* GetOznaka() const { return _oznaka; } + const char* GetUredjaj() const { return _uredjaj; } + const char* GetOpisKvara() const { return _opisKvara; } + int GetRedniBroj() const { return _redniBroj; } + Klijent& GetKlijent() { return _klijent; } + const Klijent& GetKlijent() const { return _klijent; } + Kolekcija& GetStatusi() { + return _statusi; + } + const Kolekcija& GetStatusi() + const { + return _statusi; + } + vector& GetIntervencije() { return _intervencije; } + const vector& GetIntervencije() const { + return + _intervencije; + } + StatusZahtjeva GetTrenutniStatus() const { + return + _statusi.GetElement1(_statusi.GetTrenutno() - 1); + } + friend ostream& operator<<(ostream& COUT, const ServisniZahtjev& obj) { + // ToString vraca: + // oznaka | ime i prezime klijenta | uredjaj | trenutni status + COUT << obj.ToString(); + return COUT; + } + + string ToString() const { + ostringstream buffer; + + buffer << GetOznaka() << " | " << GetKlijent().GetImePrezime() << " | " << GetUredjaj() << " | " << StatusZahtjevaNazivi[GetTrenutniStatus()] << endl; + + return buffer.str(); + } + ~ServisniZahtjev() { + delete[] _oznaka; + delete[] _uredjaj; + delete[] _opisKvara; + _oznaka = _uredjaj = _opisKvara = nullptr; + } + // : _klijent(klijent) se mora dodat ako ne zelis da se peglas sa jednom greskom vec 20 minuta :D + ServisniZahtjev(const char* uredjaj, const char* opisKvara, const Klijent& klijent, int redniBroj, const DatumVrijeme& vrijeme) : _klijent(klijent) { + _oznaka = AlocirajTekst(GenerisiOznaku(klijent.GetImePrezime().c_str(), redniBroj, vrijeme.GetGodina()).c_str()); + _uredjaj = AlocirajTekst(uredjaj); + _opisKvara = AlocirajTekst(opisKvara); + _redniBroj = redniBroj; + + _statusi.Dodaj(ZAPRIMLJEN, vrijeme); + } + + ServisniZahtjev(const ServisniZahtjev& other) : _klijent(other._klijent) { + _oznaka = AlocirajTekst(other.GetOznaka()); + _uredjaj = AlocirajTekst(other.GetUredjaj()); + _opisKvara = AlocirajTekst(other.GetOpisKvara()); + _redniBroj = other.GetRedniBroj(); + _intervencije = other.GetIntervencije(); + _statusi = other.GetStatusi(); + } + + bool DodajStatus(StatusZahtjeva status, const DatumVrijeme& vrijeme) { + DatumVrijeme posljednjeVrijeme = _statusi.GetElement2(_statusi.GetTrenutno() - 1); + StatusZahtjeva posljednjiStatus = GetTrenutniStatus(); + if (vrijeme > posljednjeVrijeme) { + if(posljednjiStatus == ZAVRSEN) { + return false; + } + else if ((int)status == (int)(posljednjiStatus + 1)) { + _statusi.Dodaj(status, vrijeme); + return true; + } + } + + return false; + } + + double UkupnaCijena() { + double sum = 0.0; + + for (const Intervencija& i : _intervencije) { + sum += i.GetCijena(); + } + + return sum; + } + + int UkupnoTrajanje() { + int sum = 0.0; + + for (const Intervencija& i : _intervencije) { + sum += i.GetTrajanjeMinuta(); + } + + return sum; + } + + + bool DodajIntervenciju(Intervencija intervencija) { + StatusZahtjeva trenutni = GetTrenutniStatus(); + if (trenutni == DIJAGNOSTIKA || trenutni == POPRAVKA) { + if (intervencija.GetCijena() > 0 && intervencija.GetTrajanjeMinuta() > 0) { + _intervencije.push_back(intervencija); + return true; + } + } + return false; + } + + +}; + + + +class Servis { + char* _naziv; + vector _zahtjevi; +public: + Servis(const char* naziv = "") { + _naziv = AlocirajTekst(naziv); + } + const char* GetNaziv() const { return _naziv; } + vector& GetZahtjevi() { return _zahtjevi; } + const vector& GetZahtjevi() const { + return + _zahtjevi; + } + ~Servis() { + delete[] _naziv; _naziv = nullptr; + } + + bool ZahtjevExist(int redniBroj) { + return any_of(_zahtjevi.begin(), _zahtjevi.end(), [&](const ServisniZahtjev& z) { + return z.GetRedniBroj() == redniBroj; + }); + } + bool ZahtjevExist(const char* oznaka) { + return any_of(_zahtjevi.begin(), _zahtjevi.end(), [&](const ServisniZahtjev& z) { + return strcmp(oznaka, z.GetOznaka()) == 0; + }); + } + + void DodajZahtjev(const ServisniZahtjev& zahtjev) { + if (ZahtjevExist(zahtjev.GetRedniBroj())) { + throw exception("zahtjev already exists"); + }; + if (ZahtjevExist(zahtjev.GetOznaka())) { + throw exception("zahtjev already exists"); + }; + _zahtjevi.push_back(zahtjev); + } + ServisniZahtjev* PronadjiZahtjev(string oznaka) { + + for (ServisniZahtjev& z : _zahtjevi) { + if (oznaka == z.GetOznaka()) { + return &z; + } + } + return nullptr; + } + + + bool EvidentirajStatus(string oznaka, StatusZahtjeva status, const DatumVrijeme& vrijeme) { + + ServisniZahtjev* zahtjev = PronadjiZahtjev(oznaka); + + if (!zahtjev) return false; + + if (zahtjev->DodajStatus(status, vrijeme)) { + thread t([&]() { + ostringstream buffer; + + buffer << " ---------------------------------------------------------------------------------" <GetKlijent().GetEmail() << endl; + buffer << "From: racuni@servis.ba" << endl; + buffer << "Subject: Servisni zahtjev zavrsen - racun" << endl; + buffer << "Postovani " << zahtjev->GetKlijent().GetImePrezime() << endl; + buffer << "Servisni zahtjev " << zahtjev->GetOznaka() << " za uredjaj " << zahtjev->GetUredjaj() << " je zavrsen." << endl; + buffer << "Ukupan iznos: " << zahtjev->UkupnaCijena() << " KM" << endl; + buffer << "Hvala na povjerenju." << endl; + + buffer << " ---------------------------------------------------------------------------------" << endl; + + cout << buffer.str(); + }); + t.join(); + return true; + } + + return false; + } + vector IzdvojiNezavrsene() { + vector nezavrseni; + + for (ServisniZahtjev& z : _zahtjevi) { + if (z.GetTrenutniStatus() != ZAVRSEN) { + nezavrseni.push_back(&z); + } + } + + return nezavrseni; + } + /* + IzracunajPrihod vraca zbir cijena svih intervencija evidentiranih + na + zahtjevima koji imaju status ZAVRSEN. Intervencije na nezavrsenim + zahtjevima ne ulaze u prihod. + */ + double IzracunajPrihod() { + double sum = 0.0; + + for (ServisniZahtjev& z : _zahtjevi) { + if (z.GetTrenutniStatus() == ZAVRSEN) { + sum += z.UkupnaCijena(); + } + } + return sum; + } + +}; + +const char* GetOdgovorNaPrvoPitanje() { + cout << "Pitanje -> Pojasnite zbog cega se operator<< implementira kao globalna a ne funkcija clanica, te na koji nacin se implementiraju prefiksalni i postfiksalni oblik operatora inkrementiranja ? \n"; + return "Odgovor -> operator<< se implementira kao globalna funkcija jer lijevi operand nije objekat naše klase, a prefiksni i postfiksni ++ razlikuju se po parametru int kod postfiksnog oblika."; +} + +const char* GetOdgovorNaDrugoPitanje() { + cout << "Pitanje -> Pojasnite nacin na koji biste, koristeci obradjene klase i metode, mogli saznati velicinu nekog tekstualnog fajla.\n"; + return "Odgovor -> Veličinu tekstualnog fajla možemo saznati otvaranjem fajla, pozicioniranjem na njegov kraj pomoću seekg() i očitavanjem pozicije pomoću tellg()"; +} + +int main() { + cout << PORUKA_TELEFON; cin.get(); + cout << PORUKA_TELEFON; cin.get(); + cout << PORUKA_ISPIT; cin.get(); + system("cls"); + cout << GetOdgovorNaPrvoPitanje() << crt; + cin.get(); + cout << GetOdgovorNaDrugoPitanje() << crt; + cin.get(); + /* + Funkcija GenerisiOznaku generise oznaku servisnog zahtjeva u +formatu: + SRV-BBB/IN-GGGG + Potpis funkcije treba biti: + string GenerisiOznaku(const char* imePrezime, int redniBroj, int +godina) + SRV -> fiksni prefiks, + BBB -> redni broj zahtjeva popunjen nulama na slobodnim mjestima, + IN -> inicijali imena i prezimena klijenta, + GGGG -> godina zaprimanja zahtjeva. + Kod imena koje sadrzi vise rijeci koriste se inicijal prve i +posljednje + rijeci. Redni broj mora biti u rasponu 1-999, a godina 2000-2099. + Za neispravne podatke funkcija vraca "SRV-000/XX-0000". + */ + if (GenerisiOznaku("Amina Buric", 42, 2026) == "SRV-042/AB-2026") + cout << "Oznaka OK" << crt; + if (GenerisiOznaku("Goran Skondric", 7, 2026) == "SRV-007/GS2026") + cout << "Oznaka OK" << crt; + if (GenerisiOznaku("Ana Marija Kovac", 156, 2027) == + "SRV-156/AK-2027") + cout << "Oznaka OK" << crt; + if (GenerisiOznaku("Amina", 42, 2026) == "SRV-000/XX-0000" && + GenerisiOznaku("Amina Buric", 0, 2026) == "SRV-000/XX-0000" && + GenerisiOznaku("Amina Buric", 1000, 2026) == "SRV-000/XX-0000" + && + GenerisiOznaku("Amina Buric", 42, 1999) == "SRV-000/XX-0000") + cout << "Neispravni podaci za oznaku OK" << crt; + /* + Koristeci regex, funkcija ValidirajOznaku provjerava prethodno + definisani + format. Prefiks mora biti SRV, redni broj mora imati tri cifre i + ne moze + biti 000, inicijali moraju biti velika slova, a godina je 2000- + 2099. + Potpis funkcije treba biti: + bool ValidirajOznaku(const string& oznaka) + */ + if (ValidirajOznaku("SRV-042/AB-2026")) + cout << "OZNAKA VALIDNA" << crt; + if (!ValidirajOznaku("SRV/042-AB-2026") && + !ValidirajOznaku("SRV-42/AB-2026") && + !ValidirajOznaku("SRV-042/Ab-2026") && + !ValidirajOznaku("SRV-000/AB-2026") && + !ValidirajOznaku("2026-SRV-042/AB")) + cout << "OZNAKA NIJE VALIDNA" << crt; + Kolekcija brojevi; + brojevi.Dodaj(10, "Deset"); + brojevi.Dodaj(20, "Dvadeset"); + brojevi.Dodaj(10, "Deset"); + brojevi.Dodaj(30, "Trideset"); + brojevi.Dodaj(20, "Dvadeset"); + cout << brojevi << crt; + /* + UkloniDuplikate vraca novu kolekciju u kojoj je zadrzano samo prvo + pojavljivanje svakog para. Par predstavlja duplikat iskljucivo ako + su + jednaki i prvi i drugi element. Originalna kolekcija ostaje + nepromijenjena. + */ + Kolekcija bezDuplikata = + brojevi.UkloniDuplikate(); + cout << "Bez duplikata:" << crt << bezDuplikata; + cout << "Original:" << crt << brojevi; + try { + Kolekcija puna; + puna.Dodaj(1, "Jedan"); + puna.Dodaj(2, "Dva"); + puna.Dodaj(3, "Tri"); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + Kolekcija kopijaBrojeva = brojevi; + kopijaBrojeva[0] = 100; + Kolekcija dodijeljeniBrojevi; + dodijeljeniBrojevi = brojevi; + dodijeljeniBrojevi.GetElement2(0) = "Izmijenjeno"; + cout << "Original:" << crt << brojevi; + cout << "Kopija:" << crt << kopijaBrojeva; + cout << "Dodijeljeni objekat:" << crt << dodijeljeniBrojevi; + DatumVrijeme zaprimljen(9, 7, 2026, 8, 0); + DatumVrijeme dijagnostika(9, 7, 2026, 9, 0); + DatumVrijeme popravka(9, 7, 2026, 10, 0); + DatumVrijeme zavrsen(9, 7, 2026, 11, 0); + /* + ToString vraca datum i vrijeme u formatu DD.MM.GGGG HH:MM, + ukljucujuci + pocetne nule. + */ + cout << zaprimljen.ToString() << crt; // 09.07.2026 08:00 + if (dijagnostika > zaprimljen) + cout << "Vrijeme dijagnostike je nakon zaprimanja" << crt; + DatumVrijeme kopijaDatuma(dijagnostika); + if (kopijaDatuma == dijagnostika && !(zaprimljen == dijagnostika)) + cout << "Provjera vremena, OK." << crt; + Klijent amina("Amina Buric", "amina@fit.ba", "061-111-222"); + Klijent goran("Goran Skondric", "goran@fit.ba", "062-222-333"); + Klijent kopijaKlijenta = amina; + cout << kopijaKlijenta << crt; + /* + Intervencija sadrzi opis, ime tehnicara, cijenu i trajanje u + minutama. + */ + Intervencija pregled("Dijagnostika uredjaja", "Haris Hadzic", 20, + 30); + Intervencija zamjenaDiska("Zamjena diska", "Haris Hadzic", 85.5, + 45); + Intervencija instalacija("Instalacija sistema", "Maja Majic", 35, + 60); + /* ToString vraca podatke u formatu: + opis | tehnicar | cijena KM | trajanje min + Zamjena diska | Haris Hadzic | 85.50 KM | 45 min + */ + cout << zamjenaDiska.ToString() << crt; + /* + Konstruktor ServisnogZahtjeva generise oznaku na osnovu klijenta, + rednog broja i godine zaprimanja, te evidentira pocetni status + ZAPRIMLJEN + sa proslijedjenim vremenom. + */ + ServisniZahtjev laptop("Laptop", "Ne pokrece se", amina, 42, + zaprimljen); + ServisniZahtjev telefon("Telefon", "Razbijen ekran", goran, 7, + zaprimljen); + /* + ToString vraca podatke u formatu: + oznaka | ime i prezime klijenta | uredjaj | trenutni status + SRV-042/AB-2026 | Amina Buric | Laptop | ZAPRIMLJEN + */ + cout << laptop.ToString() << crt; + if (laptop.ToString() == + "SRV-042/AB-2026 | Amina Buric | Laptop | ZAPRIMLJEN") + cout << "ServisniZahtjev ToString OK" << crt; + /* + DodajStatus dodaje status samo ako je vrijeme vece od vremena + posljednjeg + statusa i ako status predstavlja neposredno sljedecu fazu. + Dozvoljen slijed je: ZAPRIMLJEN -> DIJAGNOSTIKA -> POPRAVKA -> + ZAVRSEN + Preskakanje ili ponavljanje statusa nije dozvoljeno. Nakon statusa + ZAVRSEN nisu dozvoljene nove promjene. Neuspjesan pokusaj vraca + false + bez izmjene kolekcije statusa. + */ + if (!laptop.DodajStatus(POPRAVKA, dijagnostika)) + cout << "Preskakanje statusa nije dozvoljeno" << crt; + if (laptop.DodajStatus(DIJAGNOSTIKA, dijagnostika)) + cout << "Status DIJAGNOSTIKA dodan" << crt; + if (!laptop.DodajStatus(DIJAGNOSTIKA, popravka)) + cout << "Ponavljanje statusa nije dozvoljeno" << crt; + /*DodajIntervenciju dodaje intervenciju samo dok je zahtjev u + statusu + DIJAGNOSTIKA ili POPRAVKA, uz cijenu i trajanje vece od nule. + Metoda vraca true ako je intervencija dodana, u suprotnom false. + UkupnaCijena vraca zbir cijena svih intervencija, a UkupnoTrajanje + zbir + njihovih trajanja u minutama. + */ + if (laptop.DodajIntervenciju(pregled)) + cout << "Intervencija dodana" << crt; + if (laptop.DodajStatus(POPRAVKA, popravka)) + cout << "Status POPRAVKA dodan" << crt; + laptop.DodajIntervenciju(zamjenaDiska); + laptop.DodajIntervenciju(instalacija); + cout << "Ukupna cijena: " << laptop.UkupnaCijena() << " KM" << + crt; + cout << "Ukupno trajanje: " << laptop.UkupnoTrajanje() << " min" + << crt; + ServisniZahtjev kopijaLaptopa = laptop; + cout << kopijaLaptopa << crt; + Servis fitServis("FIT Servis"); + /* + DodajZahtjev dodaje zahtjev u servis. Nije dozvoljeno dodati dva + zahtjeva + sa istim rednim brojem ili istom oznakom. U slucaju duplikata + metoda + baca izuzetak. + */ + fitServis.DodajZahtjev(laptop); + fitServis.DodajZahtjev(telefon); + try { + fitServis.DodajZahtjev(telefon); + } + catch (exception& e) { + cout << "Exception: " << e.what() << crt; + } + /* + PronadjiZahtjev vraca pokazivac na zahtjev sa proslijedjenom + oznakom. + Ako zahtjev nije pronadjen, metoda vraca nullptr. + */ + string oznakaLaptopa = laptop.GetOznaka(); + ServisniZahtjev* pronadjen = + fitServis.PronadjiZahtjev(oznakaLaptopa); + if (pronadjen != nullptr) + cout << "Pronadjen zahtjev: " << pronadjen->GetOznaka() << + crt; + if (fitServis.PronadjiZahtjev("SRV-999/XX-2026") == nullptr) + cout << "Zahtjev nije pronadjen" << crt; + /* + EvidentirajStatus pronalazi zahtjev i pokusava dodati status + koristeci + pravila metode DodajStatus. + Racun se salje u zasebnom threadu iskljucivo nakon uspjesnog + evidentiranja + statusa ZAVRSEN. Za ostale statuse se ne salju obavijesti. Ako + zahtjev ne + postoji ili status nije dodan, metoda vraca false. + Primjer sadrzaja racuna: + ------------------------------------------------------------------ + --------------- + To: amina@fit.ba + From: racuni@servis.ba + Subject: Servisni zahtjev zavrsen - racun + Postovani Amina Buric, + Servisni zahtjev SRV-042/AB-2026 za uredjaj Laptop je zavrsen. + Ukupan iznos: 140.50 KM + Hvala na povjerenju. + ------------------------------------------------------------------ + --------------- + */ + if (fitServis.EvidentirajStatus(oznakaLaptopa, ZAVRSEN, zavrsen)) + cout << "Zahtjev zavrsen i racun poslan" << crt; + if (!fitServis.EvidentirajStatus( + oznakaLaptopa, ZAVRSEN, DatumVrijeme(9, 7, 2026, 12, 0))) + cout << "Ponavljanje zavrsnog statusa nije dozvoljeno" << crt; + if (!fitServis.EvidentirajStatus( + "NEPOSTOJECI", DIJAGNOSTIKA, dijagnostika)) + cout << "Status nije evidentiran za nepostojeci zahtjev" << + crt; + + /* + IzdvojiNezavrsene vraca vector pokazivaca na sve zahtjeve ciji + trenutni + status nije ZAVRSEN. + */ + vector nezavrseni = + fitServis.IzdvojiNezavrsene(); + for (auto zahtjev : nezavrseni) + cout << zahtjev->GetOznaka() << " -> " + << StatusZahtjevaNazivi[(int)zahtjev->GetTrenutniStatus()] << + crt; + /* + IzracunajPrihod vraca zbir cijena svih intervencija evidentiranih + na + zahtjevima koji imaju status ZAVRSEN. Intervencije na nezavrsenim + zahtjevima ne ulaze u prihod. + */ + cout << "Ostvareni prihod: " << fitServis.IzracunajPrihod() + << " KM" << crt; + Servis kopijaServisa = fitServis; + cout << kopijaServisa.GetNaziv() << " ima " + << kopijaServisa.GetZahtjevi().size() << " zahtjeva" << crt; + cin.get(); + return 0; +} diff --git a/Ispiti/2026-07-09/README.md b/Ispiti/2026-07-09/README.md new file mode 100644 index 0000000..b61677a --- /dev/null +++ b/Ispiti/2026-07-09/README.md @@ -0,0 +1,12 @@ +# Grupa 1 + +- enum VrstaDostave { STANDARDNA, BRZA, MEDJUNARODNA }; +- enum StatusPosiljke { KREIRANA, PREUZETA, U_TRANZITU, ISPORUCENA, OTKAZANA }; +- Kolekcija statički niz pointera (T* elementi[max]) +- string, vector, advanced regex, generisi oznaku, threadovi + +# Grupa 2 + +- enum StatusZahtjeva { ZAPRIMLJEN, DIJAGNOSTIKA, POPRAVKA, ZAVRSEN }; +- Kolekcija pointer na dinamicki niz (T* elementi) +- string, vector, advanced regex, generisi oznaku, threadovi