﻿#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>

using namespace std;

class StaffMember {
public:
    string name;
    string department;
    int number;

    StaffMember(string name, string department, int number) {
        this->name = name;
        this->department = department;
        this->number = number;
    }
};

class Card {
public:
    int number;
    string type;
    string date;
    StaffMember* staffMember;

    Card(int number, string type, string date, StaffMember* staffMember) {
        this->number = number;
        this->type = type;
        this->date = date;
        this->staffMember = staffMember;
    }
};

class Barrier {
private:
    bool isOpen;
public:
    Barrier() {
        this->isOpen = false;
    }

    void open() {
        this->isOpen = true;
    }

    void close() {
        this->isOpen = false;
    }

    bool isOpened() {
        return isOpen;
    }
};

class Sensor {
public:
    bool isActivated() {
        // implementation to check if sensor is activated
        return true;
    }
};

class IDReader {
public:
    virtual Card* readCard() {
        // implementation to read card
        return NULL;
    }

    virtual bool isCardRecognized(Card* card) {
        // implementation to check if card is recognized by the system
        return true;
    }
};

class NumplateReader : public IDReader {
public:
    Card* readCard() override {
        // implementation to read car's number plate and create a temporary card
        Card* tempCard = new Card(0, "Temporary", "", NULL);
        return tempCard;
    }
};

class FullSign {
public:
    bool isDisplayed() {
        // implementation to check if sign is displayed
        return true;
    }

    void display() {
        // implementation to display sign
    }

    void hide() {
        // implementation to hide sign
    }
};

class CarPark {
private:
    vector<Card*> cards;
    unordered_set<string> numberplates; // added dynamic data structure to store numberplates
    int maxCapacity;
    int currentCapacity;
    Barrier* entranceBarrier;
    Barrier* exitBarrier;
    IDReader* idReader;
    FullSign* fullSign;
public:
    CarPark(int maxCapacity, IDReader* idReader) {
        this->maxCapacity = maxCapacity;
        this->currentCapacity = 0;
        this->entranceBarrier = new Barrier();
        this->exitBarrier = new Barrier();
        this->idReader = idReader;
        this->fullSign = new FullSign();
    }

    bool isFull() {
        return currentCapacity >= maxCapacity;
    }

    bool insertCard(Card* card) {
        if (isFull()) {
            fullSign->display();
            return false;
        }
        cards.push_back(card);
        numberplates.insert(to_string(card->number)); // add numberplate to set
        currentCapacity++;
        entranceBarrier->open();
        return true;
    }

    bool removeCard(Card* card) {
        for (int i = 0; i < cards.size(); i++) {
            if (cards[i] == card) {
                cards.erase(cards.begin() + i);
                numberplates.erase(to_string(card->number)); // remove numberplate from set
                currentCapacity--;
                exitBarrier->open();
                return true;
            }
        }
        return false;
    }

    bool process
    (Sensor* entranceSensor, Sensor* exitSensor) {
        while (true) {
            // check if a car is approaching the entrance
            if (entranceSensor->isActivated()) {
                entranceBarrier->close();
                Card* card = idReader->readCard();
                if (idReader->isCardRecognized(card)) {
                    insertCard(card);
                }
                else {
                    delete card;
                }
            }
            // check if a car is approaching the exit
            else if (exitSensor->isActivated()) {
                exitBarrier->close();
                Card* card = idReader->readCard();
                if (numberplates.find(to_string(card->number)) != numberplates.end()) {
                    removeCard(card);
                    delete card;
                }
                else {
                    exitBarrier->open();
                    delete card;
                }
            }
            // wait for some time before checking again
            else {
                fullSign->hide();
                entranceBarrier->open();
                exitBarrier->open();
                // wait for 1 second

            }
        }
    }
};

int main() {
    StaffMember* staff = new StaffMember("John Doe", "Marketing", 123);
    Card* card = new Card(123456, "Staff", "", staff);
    IDReader* idReader = new NumplateReader();
    CarPark* carPark = new CarPark(10, idReader);
    Sensor* entranceSensor = new Sensor();
    Sensor* exitSensor = new Sensor();
    carPark->process(entranceSensor, exitSensor);
    return 0;
}