# Наследование. Делегирование Delegating.

from functools import total_ordering

class Person:

    def __init__(self, name, surname) -> None:
        self.name = name
        self.surname = surname

    def __str__(self):
        return f"Person {self.name} {self.surname}"
    
    def info(self):
        print("Parent class")
        print(self)

    def breath(self):
        print('Человек дышит')


class Doctor(Person):

    def __init__(self, name, surname, age):
        super().__init__(name, surname)
        self.age = age

    def __str__(self):
        return f"Doctor {self.name} {self.surname}"

    def breath(self):
        super().breath()
        print("Доктор дышит")



class Rectangle:
    
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

    def perimeter(self):
        return 2 * self.length + 2 * self.width


class Square(Rectangle):

    def __init__(self, side):
        super().__init__(side, side)



class Person:

    def __init__(self, name, passport):
        self.name = name
        self.passport = passport

    def display(self):
        print(f"{self.name}: {self.passport}")


class Employee(Person):
    
    def __init__(self, name, passport, salary, department):
        super().__init__(name, passport)
        self.salary = salary
        self.department = department


class Vehicle:

    def __init__(self, name, mileage, capacity):
        self.name = name
        self.mileage = mileage
        self.capacity = capacity

    def fare(self):
        return self.capacity * 100
    
    def display(self):
        print(f"Total {self.name} fare is: {self.fare()}")


class Bus(Vehicle):

    def __init__(self, name, mileage):
        super().__init__(name, mileage, 50)

    def fare(self):
        return super().fare() * 1.1
    

class Taxi(Vehicle):

    def __init__(self, name, mileage):
        super().__init__(name, mileage, 4)

    def fare(self):
        return super().fare() * 1.35


class Transport:

    def __init__(self, brand, max_speed, kind=None):
        self.brand = brand
        self.max_speed = max_speed
        self.kind = kind

    def __str__(self):
        return f"Тип транспорта {self.kind} марки {self.brand} может развить скорость {self.max_speed} км/ч"
    

class Car(Transport):

    def __init__(self, brand, max_speed, mileage, gasoline_residue):
        super().__init__(brand, max_speed, kind='Car')
        self.mileage = mileage
        self.__gasoline_residue = gasoline_residue

    @property
    def gasoline(self):
        return f"Осталось бензина {self.__gasoline_residue} л"
    
    @gasoline.setter
    def gasoline(self, value):
        if not isinstance(value, int):
            print('Ошибка заправки автомобиля')
        else:
            self.__gasoline_residue += value
            print(f"Объем топлива увеличен на {value} л и составляет {self.__gasoline_residue} л")


class Boat(Transport):

    def __init__(self, brand, max_speed, owners_name):
        super().__init__(brand, max_speed, kind='Boat')
        self.owners_name = owners_name

    def __str__(self):
        return f"Этой лодкой марки {self.brand} владеет {self.owners_name}"
    

class Plane(Transport):

    def __init__(self, brand, max_speed, capacity):
        super().__init__(brand, max_speed, kind='Plane')
        self.capacity = capacity

    def __str__(self):
        return f"Самолет марки {self.brand} вмещает в себя {self.capacity} людей"



class Initialization:

    def __init__(self, capacity, food: list[str]):
        if not isinstance(capacity, int):
            print('Количество людей должно быть целым числом')
        else:
            self.capacity = capacity
            self.food = food


class Vegetarian(Initialization):

    def __init__(self, capacity, food: list[str]):
        super().__init__(capacity, food)

    def __str__(self):
        return f"{self.capacity} людей предпочитают не есть мясо! Они предпочитают {self.food}"
    

class MeatEater(Initialization):

    def __init__(self, capacity, food: list[str]):
        super().__init__(capacity, food)

    def __str__(self):
        return f"{self.capacity} мясоедов в Москве! Помимо мяса они едят еще и {self.food}"
    
@total_ordering
class SweetTooth(Initialization):

    def __init__(self, capacity, food: list[str]):
        super().__init__(capacity, food)

    def __str__(self):
        return f"Сладкоежек в Москве {self.capacity}. Их самая любимая еда: {self.food}"

    def __eq__(self, value):
        if isinstance(value, int):
            return self.capacity == value
        elif isinstance(value, (Initialization)):
            return self.capacity == value.capacity
        else:
            return f"Невозможно сравнить количество сладкоежек с {value}"

    def __lt__(self, value):
        if isinstance(value, int):
            return self.capacity < value
        elif isinstance(value, (Initialization)):
            return self.capacity < value.capacity
        else:
            return f"Невозможно сравнить количество сладкоежек с {value}"
        


def main():

    p1 = Initialization('Chuck', [])
    assert isinstance(p1, Initialization)
    assert not hasattr(p1, 'capacity'), 'Не нужно создавать атрибут "capacity", если передается не целое число'
    assert not hasattr(p1, 'food'), 'Не нужно создавать атрибут "food", если передается не целое число'

    c1 = Vegetarian(100, [1, 2, 3])
    print(c1)
    assert isinstance(c1, Vegetarian)
    assert c1.capacity == 100
    assert c1.food == [1, 2, 3]

    b1 = MeatEater(1000, ['Arkasha'])
    print(b1)
    assert isinstance(b1, MeatEater)
    assert b1.capacity == 1000
    assert b1.food == ['Arkasha']

    pla = SweetTooth(444, [2150, 777])
    print(pla)
    assert isinstance(pla, SweetTooth)
    assert pla.capacity == 444
    assert pla.food == [2150, 777]
    assert pla > 100
    assert not pla < 80
    assert not pla == 90
    assert pla > c1
    assert not pla < c1
    assert not pla == c1
    assert not pla > b1
    assert pla < b1
    assert not pla == b1

    v_first = Vegetarian(10000, ['Орехи', 'овощи', 'фрукты'])
    print(v_first)  # 10000 людей предпочитают не есть мясо! Они предпочитают ['Орехи', 'овощи', 'фрукты']
    v_second = Vegetarian([23], ['nothing'])  # Количество людей должно быть целым числом

    m_first = MeatEater(15000, ['Жареную картошку', 'рыба'])
    print(m_first)  # 15000 мясоедов в Москве! Помимо мяса они едят еще и ['Жареную картошку', 'рыба']
    s_first = SweetTooth(30000, ['Мороженое', 'Чипсы', 'ШОКОЛАД'])
    print(s_first)  # Сладкоежек в Москве 30000. Их самая любимая еда: ['Мороженое', 'Чипсы', 'ШОКОЛАД']
    print(s_first > v_first)  # Сладкоежек больше, чем людей с другим вкусовым предпочтением
    print(30000 == s_first)  # Количество сладкоежек из опрошенных людей совпадает с 30000
    print(s_first == 25000)  # Количество людей не совпадает
    print(100000 < s_first)  # Количество сладкоежек в Москве не больше, чем 100000
    print(100 < s_first)  # Количество сладкоежек больше, чем 100

    '''
    p1 = Transport('Chuck', 50)
    print(p1)
    assert isinstance(p1, Transport)
    assert p1.kind == None
    assert p1.brand == 'Chuck'
    assert p1.max_speed == 50
    assert p1.__dict__ == {'kind': None, 'brand': 'Chuck', 'max_speed': 50}

    c1 = Car('RRR', 50, 150, 999)
    print(c1)

    assert isinstance(c1, Car)
    assert c1.kind == "Car"
    assert c1.brand == 'RRR'
    assert c1.max_speed == 50
    assert c1.mileage == 150
    assert c1.gasoline == 'Осталось бензина 999 л'
    c1.gasoline = 100
    assert c1.gasoline == 'Осталось бензина 1099 л'
    assert c1.__dict__ == {'kind': 'Car', 'brand': 'RRR', 'max_speed': 50,
                        'mileage': 150, '_Car__gasoline_residue': 1099}

    b1 = Boat('XXX', 1150, 'Arkasha')
    print(b1)
    assert isinstance(b1, Boat)
    assert b1.kind == "Boat"
    assert b1.brand == 'XXX'
    assert b1.max_speed == 1150
    assert b1.owners_name == 'Arkasha'

    pla = Plane('www', 2150, 777)
    print(pla)
    assert isinstance(pla, Plane)
    assert pla.kind == "Plane"
    assert pla.brand == 'www'
    assert pla.max_speed == 2150
    assert pla.capacity == 777

    transport = Transport('Telega', 10)
    print(transport)  # Тип транспорта None марки Telega может развить скорость 10 км/ч
    bike = Transport('shkolnik', 20, 'bike')
    print(bike)  # Тип транспорта bike марки shkolnik может развить скорость 20 км/ч

    first_plane = Plane('Virgin Atlantic', 700, 450)
    print(first_plane)  # Самолет марки Virgin Atlantic может вмещать в себя 450 людей
    first_car = Car('BMW', 230, 75000, 300)
    print(first_car)  # Тип транспорта Car марки BMW может развить скорость 230 км/ч
    print(first_car.gasoline)  # Осталось бензина на 300 км
    first_car.gasoline = 20  # Печатает 'Объем топлива увеличен на 20 л и составляет 320 л'
    print(first_car.gasoline)  # Осталось бензина на 350 км
    second_car = Car('Audi', 230, 70000, 130)
    second_car.gasoline = [None]  # Печатает 'Ошибка заправки автомобиля'
    first_boat = Boat('Yamaha', 40, 'Petr')
    print(first_boat)  # Этой лодкой марки Yamaha владеет Petr
    '''


    '''
    sc = Vehicle('Scooter', 100, 2)
    sc.display()

    merc = Bus("Mercedes", 120000)
    merc.display()

    polo = Taxi("Volkswagen Polo", 15000)
    polo.display()

    t = Taxi('x', 111)
    assert t.__dict__ == {'name': 'x', 'mileage': 111, 'capacity': 4}
    t.display()
    b = Bus('t', 123)
    assert b.__dict__ == {'name': 't', 'mileage': 123, 'capacity': 50}
    b.display()
    '''

    '''
    assert issubclass(Employee, Person)

    emp = Person("just human", 123456)
    emp.display()
    assert emp.__dict__ == {'name': 'just human', 'passport': 123456}

    emp2 = Employee("Geek2", 534432, 321321, 'Roga & Koputa')
    emp2.display()
    assert emp2.__dict__ == {'salary': 321321, 'department': 'Roga & Koputa',
                            'name': 'Geek2', 'passport': 534432}
    '''

    '''
    rect_1 = Rectangle(3, 2)
    assert rect_1.area() == 6
    assert rect_1.perimeter() == 10

    rect_2 = Rectangle(10, 5)
    assert rect_2.area() == 50
    assert rect_2.perimeter() == 30

    sq_1 = Square(4)
    assert sq_1.area() == 16
    assert sq_1.perimeter() == 16

    sq_2 = Square(10)
    assert sq_2.area() == 100
    assert sq_2.perimeter() == 40
    print('Good')
    '''

    '''
    p = Person('Ivan', 'Ivanov')
    d = Doctor('Petr', 'Petrov', 25)
    d.info()
    '''
    

if __name__ == '__main__':
    main()