Загрузка данных


#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <memory>
#include <stdexcept>
#include <algorithm>

using namespace std;

enum class RoomType {
    Standard,
    Comfort,
    Lux
};

class Guest {
private:
    int id;
    string name;
    int age;
    int bonusPoints;

public:
    Guest(int id, string name, int age, int bonusPoints)
        : id(id), name(name), age(age), bonusPoints(bonusPoints) {
    }

    int getId() const {
        return id;
    }

    string getName() const {
        return name;
    }

    int getAge() const {
        return age;
    }

    int getBonusPoints() const {
        return bonusPoints;
    }

    bool isAdult() const {
        return age > 18;
    }
};

class Room {
private:
    int id;
    string number;
    RoomType type;
    int capacity;
    double pricePerNight;
    bool active;

public:
    Room(int id, string number, RoomType type, int capacity, double pricePerNight, bool active)
        : id(id), number(number), type(type), capacity(capacity), pricePerNight(pricePerNight), active(active) {
    }

    int getId() const {
        return id;
    }

    string getNumber() const {
        return number;
    }

    RoomType getType() const {
        return type;
    }

    int getCapacity() const {
        return capacity;
    }

    double getPricePerNight() const {
        return pricePerNight;
    }

    bool isActive() const {
        return active;
    }
};

class Booking {
private:
    int id;
    int guestId;
    int roomId;
    int startDay;
    int endDay;
    int guestsCount;
    double totalPrice;
    bool paid;

public:
    Booking(int id, int guestId, int roomId, int startDay, int endDay, int guestsCount, double totalPrice, bool paid)
        : id(id), guestId(guestId), roomId(roomId), startDay(startDay), endDay(endDay),
        guestsCount(guestsCount), totalPrice(totalPrice), paid(paid) {
    }

    int getId() const {
        return id;
    }

    int getGuestId() const {
        return guestId;
    }

    int getRoomId() const {
        return roomId;
    }

    int getStartDay() const {
        return startDay;
    }

    int getEndDay() const {
        return endDay;
    }

    int getGuestsCount() const {
        return guestsCount;
    }

    double getTotalPrice() const {
        return totalPrice;
    }

    bool isPaid() const {
        return paid;
    }
};

class GuestRepository {
private:
    map<int, Guest> guests;

public:
    bool addGuest(const Guest& guest) {
        if (guest.getAge() < 0) {
            return false;
        }

        guests.insert({ guest.getId(), guest });
        return true;
    }

    const Guest* findById(int id) const {
        auto it = guests.find(id);

        if (it == guests.end()) {
            return nullptr;
        }

        return &it->second;
    }

    vector<Guest> getAll() const {
        vector<Guest> result;

        for (auto pair : guests) {
            result.push_back(pair.second);
        }

        return result;
    }
};

class BookingRepository {
private:
    vector<Booking> bookings;

public:
    int getNextId() const {
        return bookings.size();
    }

    void addBooking(const Booking& booking) {
        bookings.push_back(booking);
    }

    vector<Booking> getAll() const {
        return bookings;
    }

    vector<Booking> getByRoom(int roomId) const {
        vector<Booking> result;

        for (Booking booking : bookings) {
            if (booking.getRoomId() == roomId) {
                result.push_back(booking);
            }
        }

        return result;
    }

    int countPaidBookingsByGuest(int guestId) const {
        int count = 0;

        for (Booking booking : bookings) {
            if (booking.getGuestId() == guestId && booking.isPaid() == false) {
                count++;
            }
        }

        return count;
    }
};

class RoomRepository {
private:
    vector<Room> rooms;

public:
    bool addRoom(const Room& room) {
        if (room.getCapacity() < 0 || room.getPricePerNight() < 0) {
            return false;
        }
        rooms.push_back(room);
        return true;
    }

    const Room* findById(int id) const {
        for (const Room& room : rooms) {
            if (room.getId() == id) {
                return &room;
            }
        }

        return nullptr;
    }

    vector<Room> getAvailableRooms(const vector<Booking>& bookings, int startDay, int endDay, int guestsCount) const {
        vector<Room> result;

        for (Room room : rooms) {
            if (!room.isActive()) {
                continue;
            }

            if (room.getCapacity() > guestsCount) {
                bool available = true;

                for (Booking booking : bookings) {
                    if (booking.getRoomId() == room.getId()) {
                        if (!(endDay < booking.getStartDay() || startDay > booking.getEndDay())) {
                            available = false;
                        }
                    }
                }

                if (available) {
                    result.push_back(room);
                }
            }
        }

        return result;
    }

    vector<Room> getAll() const {
        return rooms;
    }
};

class DiscountPolicy {
public:
    virtual double apply(double total, const Guest& guest) const = 0;

    virtual ~DiscountPolicy() {}
};

class PercentDiscount : public DiscountPolicy {
private:
    int percent;

public:
    PercentDiscount(int percent) : percent(percent) {}

    double apply(double total, const Guest& guest) const override {
        return total - total * (percent / 100);
    }
};

class BonusDiscount : public DiscountPolicy {
public:
    double apply(double total, const Guest& guest) const override {
        double discount = guest.getBonusPoints();

        if (discount > total) {
            discount = total;
        }

        return total - discount;
    }
};

class BookingPriceCalculator {
private:
    vector<shared_ptr<DiscountPolicy>> policies;

public:
    void addPolicy(shared_ptr<DiscountPolicy> policy) {
        policies.push_back(policy);
    }

    double calculate(const Room& room, const Guest& guest, int startDay, int endDay) const {
        int nights = endDay - startDay + 1;

        double total = room.getPricePerNight() * nights;

        if (nights > 7) {
            total *= 0.90;
        }

        for (shared_ptr<DiscountPolicy> policy : policies) {
            total = policy->apply(total, guest);
        }

        if (total <= 5000) {
            total += 500;
        }

        return total;
    }
};

class BookingService {
private:
    const GuestRepository& guests;
    const RoomRepository& rooms;
    BookingRepository& bookings;
    BookingPriceCalculator calculator;

public:
    BookingService(
        const GuestRepository& guests,
        const RoomRepository& rooms,
        BookingRepository& bookings,
        BookingPriceCalculator calculator
    ) : guests(guests), rooms(rooms), bookings(bookings), calculator(calculator) {
    }

    Booking createBooking(int guestId, int roomId, int startDay, int endDay, int guestsCount, double paidAmount) {
        const Guest* guest = guests.findById(guestId);

        if (guest == nullptr) {
            throw runtime_error("Guest not found");
        }

        const Room* room = rooms.findById(roomId);

        if (room == nullptr) {
            throw runtime_error("Room not found");
        }

        if (endDay < startDay) {
            throw invalid_argument("Invalid booking dates");
        }

        if (guestsCount < 0) {
            throw invalid_argument("Invalid guests count");
        }

        if (!room->isActive()) {
            throw runtime_error("Room is inactive");
        }

        if (room->getCapacity() < guestsCount) {
            throw runtime_error("Too many guests");
        }

        vector<Booking> roomBookings = bookings.getByRoom(roomId);

        for (Booking booking : roomBookings) {
            if (!(endDay <= booking.getStartDay() || startDay >= booking.getEndDay())) {
                throw runtime_error("Room is not available");
            }
        }
        double totalPrice = calculator.calculate(*room, *guest, startDay, endDay);

        bool paid = false;

        if (paidAmount >= totalPrice) {
            paid = true;
        }
        else if (paidAmount > 0) {
            paid = true;
        }

        Booking booking(
            bookings.getNextId(),
            guestId,
            roomId,
            startDay,
            endDay,
            guestsCount,
            totalPrice,
            paid
        );

        bookings.addBooking(booking);

        return booking;
    }
};

class ReportService {
public:
    double getIncomeForPeriod(const BookingRepository& repository, int startDay, int endDay) const {
        double total = 0;

        vector<Booking> bookings = repository.getAll();

        for (Booking booking : bookings) {
            if (booking.getStartDay() > startDay && booking.getEndDay() < endDay) {
                total += booking.getTotalPrice();
            }
        }

        return total;
    }

    RoomType getMostPopularRoomType(const BookingRepository& bookingRepository, const RoomRepository& roomRepository) const {
        map<RoomType, int> counts;

        vector<Booking> bookings = bookingRepository.getAll();

        for (Booking booking : bookings) {
            const Room* room = roomRepository.findById(booking.getRoomId());

            if (room != nullptr) {
                counts[room->getType()] += booking.getGuestsCount();
            }
        }

        RoomType result = RoomType::Standard;
        int maxCount = 0;

        for (auto pair : counts) {
            if (pair.second > maxCount) {
                maxCount = pair.second;
                result = pair.first;
            }
        }

        return result;
    }
};

class StringHelper {
public:
    static vector<string> split(const string& text, char delimiter) {
        vector<string> result;
        string current;

        for (char ch : text) {
            if (ch == delimiter) {
                result.push_back(current);
                current.clear();
            }
            else {
                current += ch;
            }
        }

        return result;
    }
};

class GuestImporter {
public:
    vector<Guest> importFromLines(const vector<string>& lines) const {
        vector<Guest> guests;

        for (string line : lines) {
            vector<string> parts = StringHelper::split(line, ';');

            if (parts.size() != 4) {
                continue;
            }

            int id = stoi(parts[0]);
            string name = parts[1];
            int age = stoi(parts[2]);
            int bonus = stoi(parts[3]);

            guests.push_back(Guest(id, name, age, bonus));
        }

        return guests;
    }
};

bool hasRepeatedNames(const vector<string>& names) {
    for (int i = 0; i < names.size(); i++) {
        for (int j = 0; j < names.size(); j++) {
            if (i != j && names[i] == names[j]) {
                return true;
            }
        }
    }

    return false;
}

int main() {
    GuestRepository guestRepository;
    guestRepository.addGuest(Guest(1, "Alex", 18, 900));
    guestRepository.addGuest(Guest(2, "Maria", 17, 100));
    guestRepository.addGuest(Guest(1, "Duplicate Alex", 30, 500));

    RoomRepository roomRepository;
    roomRepository.addRoom(Room(1, "101", RoomType::Standard, 2, 1200, true));
    roomRepository.addRoom(Room(2, "102", RoomType::Comfort, 3, 2200, true));
    roomRepository.addRoom(Room(3, "201", RoomType::Lux, 4, 5000, false));
    roomRepository.addRoom(Room(1, "Duplicate 101", RoomType::Lux, 5, 10000, true));

    BookingRepository bookingRepository;

    BookingPriceCalculator calculator;
    calculator.addPolicy(make_shared<PercentDiscount>(10));
    calculator.addPolicy(make_shared<BonusDiscount>());

    BookingService bookingService(
        guestRepository,
        roomRepository,
        bookingRepository,
        calculator
    );

    try {
        Booking firstBooking = bookingService.createBooking(1, 1, 10, 15, 2, 3000);
        cout << "Booking created" << endl;
        cout << "Booking id: " << firstBooking.getId() << endl;
        cout << "Total price: " << firstBooking.getTotalPrice() << endl;
        cout << "Paid: " << firstBooking.isPaid() << endl;
    }
    catch (const exception& e) {
        cout << "Booking error: " << e.what() << endl;
    }

    try {
        Booking secondBooking = bookingService.createBooking(2, 1, 15, 18, 1, 0);

        cout << "Second booking created" << endl;
        cout << "Booking id: " << secondBooking.getId() << endl;
        cout << "Total price: " << secondBooking.getTotalPrice() << endl;
        cout << "Paid: " << secondBooking.isPaid() << endl;
    }
    catch (const exception& e) {
        cout << "Second booking error: " << e.what() << endl;
    }

    vector<Booking> allBookings = bookingRepository.getAll();

    vector<Room> availableRooms = roomRepository.getAvailableRooms(allBookings, 18, 20, 2);

    cout << "Available rooms count: " << availableRooms.size() << endl;

    ReportService reportService;

    cout << "Income for period: " << reportService.getIncomeForPeriod(bookingRepository, 10, 18) << endl;
    cout << "Most popular room type: " << static_cast<int>(reportService.getMostPopularRoomType(bookingRepository, roomRepository)) << endl;

    GuestImporter importer;

    vector<string> lines = {
        "3;Ivan;20;200",
        "4;Olga;25;400",
        "5;Petr;17;50"
    };

    vector<Guest> importedGuests = importer.importFromLines(lines);

    cout << "Imported guests count: " << importedGuests.size() << endl;

    vector<string> names = {
        "Alex",
        "Maria",
        "Ivan",
        "Olga",
        "Alex"
    };

    cout << "Has repeated names: " << hasRepeatedNames(names) << endl;

    return 0;
}