# EG11-11 Klasa FashionShop

import pickle

from BTCInput import *

class StockItem(object):
    '''
    Towar magazynowy dla sklepu z odzieżą
    '''

    show_instrumentation = False
    
    min_price = 0.5
    max_price = 500.0

    max_stock_add = 50

    def __init__(self, stock_ref, price, color, location):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __init__ klasy StockItem')
        self.stock_ref = stock_ref
        self.__price = price
        self.__stock_level = 0
        self.StockItem_version = 1
        self.color = color
        self.location = location

    @property
    def item_name(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę get właściwości item_name klasy StockItem')
        return 'Towar magazynowy'
        
    def check_version(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę check_version klasy StockItem')
        # To jest wersja 1 — nie ma potrzeby aktualizowania czegokolwiek
        pass

    def __str__(self): 
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __str__ klasy StockItem')
        template = '''Numer magazynowy: {0}
Typ: {1}
Lokalizacja: {2}
Cena: {3}
Stan magazynowy: {4}
Kolor: {5}''' 

        return template.format(self.stock_ref, self.item_name, self.location,
                                self.price, self.stock_level, self.color) 

    def add_stock(self,count):
        '''
        Dostawa towaru do magazynu 
        count oznacza liczbę sztuk towaru do dodania
        Zgłasza wyjątek, jeśli liczba jest nieprawidłowa.
        '''
        if StockItem.show_instrumentation:
            print('**Wywołano metodę add_stock klasy StockItem')
        if count < 0 or count > StockItem.max_stock_add:
            raise Exception('Nieprawidłowa liczba sztuk towaru do dodania')

        self.__stock_level = self.__stock_level + count

    def sell_stock(self, count):
        '''
        Sprzedaż towaru.
        count oznacza liczbę sztuk towaru do sprzedania
        Zgłasza wyjątek, jeśli liczba jest nieprawidłowa.
        '''
        if StockItem.show_instrumentation:
            print('**Wywołano metodę sell_stock klasy StockItem')
        if count < 1:
            raise Exception('Nieprawidłowa liczba sztuk towaru do sprzedaży')

        if count > self.stock_level:
            raise Exception('Za mało towaru w magazynie')

        self.__stock_level = self.__stock_level - count

    def set_price(self, new_price):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę set_price klasy StockItem')
        if price < StockItem.min_price or price > StockItem.max_price:
            raise Exception('Nieprawidłowa cena')
        self.__price = new_price

    @property
    def price(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę get właściwości price klasy StockItem')
        return self.__price

    @property
    def stock_level(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę get właściwości stock_level klasy StockItem')
        return self.__stock_level


class Dress(StockItem):

    def __init__(self, stock_ref, price, color, pattern, size, location):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __init__ klasy Dress')
        super().__init__(stock_ref=stock_ref, price=price,
                         color=color, location=location)
        self.pattern = pattern
        self.size = size
        self.Dress_version = 1

    @property
    def item_name(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę get właściwości item_name klasy Dress')
        return 'Sukienka'
        
    def check_version(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę check_version klasy Dress')
        # To jest wersja 1 — nie ma potrzeby aktualizowania czegokolwiek
        super().check_version()
        pass

    def __str__(self):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __str__ klasy Dress')
        stock_details = super().__str__()
        template = '''{0}
Fason: {1}
Rozmiar: {2}'''
        return template.format(stock_details, self.pattern,
                               self.size)
 

class Pants(StockItem):

    def __init__(self, stock_ref, price, color, pattern, length, waist, location):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __init__ klasy Pants')
        super().__init__(stock_ref=stock_ref, price=price,
                         color=color, location=location)
        self.pattern = pattern
        self.length = length
        self.waist = waist
        self.pants_version = 1

    @property
    def item_name(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę get właściwości item_name klasy Pants')
        return 'Spodnie'

    def check_version(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę check_version klasy Pants')
        # To jest wersja 1 — nie ma potrzeby aktualizowania czegokolwiek
        super().check_version()
        pass

    def __str__(self):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __str__ klasy Pants')
        stock_details = super().__str__()
        template = '''{0}
Fason: {1}
Długość: {2}
Obwód pasa: {3}'''
        return template.format(stock_details, self.pattern,
                               self.length, self.waist)


class Jeans(Pants):

    def __init__(self, stock_ref, price, color, pattern, length, waist, style, location):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __init__ Jeans')
        super().__init__(stock_ref=stock_ref, price=price,
                         color=color, pattern=pattern, length=length,
                         waist=waist, location=location)
        self.style = style
        self.jeans_version = 1

    @property
    def item_name(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę get właściwości item_name klasy Jeans')
        return 'Dżinsy'

    def check_version(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę check_version klasy Jeans')
        # To jest wersja 1 — nie ma potrzeby aktualizowania czegokolwiek
        super().check_version()
        pass

    def __str__(self):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __str__ klasy Jeans')
        pants_details = super().__str__()
        template = '''{0}
Styl: {1}'''
        return template.format(pants_details, self.style)


class Hat(StockItem):

    def __init__(self, stock_ref, price, color, size, location):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __init__ klasy Hat')
        super().__init__(stock_ref=stock_ref, price=price,
                         color=color, location=location)
        self.size = size
        self.Hat_version = 1

    @property
    def item_name(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę get właściwości item_name klasy Hat')
        return 'Kapelusz'

    def check_version(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę check_version klasy Hat')
        # To jest wersja 1 — nie ma potrzeby aktualizowania czegokolwiek
        super().check_version()
        pass

    def __str__(self):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __str__ klasy Hat')
        stock_details = super().__str__()
        template = '''{0}
Rozmiar: {1}'''
        return template.format(stock_details, self.size)

    @staticmethod
    def make_test_data():
        '''
        Zwraca testowy kapelusz - po jednym
        '''
        stock_id = 1
        for price in [50,100,200,500]:
            for color in ['czerwony', 'zielony', 'niebieski', 'żółty', 'różowy']:
                for pattern in ['prosty', 'krata', 'paski']:
                    for size in [6, 7, 8, 9]:
                        id_string = 'HA' + str(stock_id)
                        h = Hat(id_string, price, color, size, 'hat shelf')
                        stock_id = stock_id + 1
                        yield h

class Blouse(StockItem):
    
    def __init__(self, stock_ref, price, color, size, style, pattern, location):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __init__ klasy Blouse')
        super().__init__(stock_ref, price, color, location)
        self.size = size
        self.style = style
        self.pattern = pattern
        self.Hat_version = 1

    @property
    def item_name(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę get właściwości item_name klasy Blouse')
        return 'Bluza'

    def check_version(self):
        if StockItem.show_instrumentation:
            print('** Wywołano metodę check_version klasy Blouse')
        # To jest wersja 1 — nie ma potrzeby aktualizowania czegokolwiek
        super().check_version()
        pass

    def __str__(self):
        if StockItem.show_instrumentation:
            print('**Wywołano metodę __str__ klasy Blouse')
        stock_details = super().__str__()
        template = '''{0}
Rozmiar: {1}
Styl: {2}
Fason: {3}'''
        return template.format(stock_details, self.size,
                               self.style, self.pattern)

import pickle


class FashionShop:

    show_instrumentation = False

    def __init__(self):
        if FashionShop.show_instrumentation:
            print('**Wywołano metodę __init__ klasy FashionShop')
        self.__stock_dictionary = {}

    def save(self, filename):
        '''
        Zapisuje kontakty w pliku o podanej nazwie
        Dane są przechowywane w postaci binarnej, w pliku .pickle
        Jeśli zapis się nie powiedzie, program zgłosi wyjątki
        '''
        if FashionShop.show_instrumentation:
            print('**Wywołano metodę save klasy FashionShop')
        with open(filename,'wb') as out_file:
            pickle.dump(self,out_file)

    @staticmethod
    def load(filename):
        '''
        Ładuje dane sklepu z odzieżą z pliku o podanej nazwie
        Dane są przechowywane w postaci binarnej, w pliku .pickle
        Jeśli ładowanie pliku się nie powiedzie, funkcja będzie zgłaszała wyjątki
        '''
        if FashionShop.show_instrumentation:
            print('**Wywołano metodę load klasy FashionShop')
        with open(filename,'rb') as input_file:
            result = pickle.load(input_file)

        # Teraz zaktualizuj wersje załadowanych obiektów towarów
        for stock_item in result.__stock_dictionary.values():
            stock_item.check_version()
        return result


    def store_new_stock_item(self, stock_item):
        '''
        Utworzenie nowego towaru w sklepie z odzieżą
        Towary są indeksowane za pomocą wartości atrybutu stock_ref
        Zgłasza wyjątek, jeśli towar jest już zapisany w aplikacji Modny ciuch.
        '''
        if FashionShop.show_instrumentation:
            print('**Wywołano metodę store_new_stock klasy StockItem')
        if stock_item.stock_ref in self.__stock_dictionary:
            raise Exception('Towar istnieje') 
        self.__stock_dictionary[stock_item.stock_ref] = stock_item


    def find_stock_item(self, stock_ref):
        '''
        Pobiera towar ze słownika 
        Zwraca None, jeśli nie ma pozycji dla 
        takiego klucza
        '''
        if FashionShop.show_instrumentation:
            print('**Wywołano metodę find_stock_item klasy StockItem')
        if stock_ref in self.__stock_dictionary:
            return self.__stock_dictionary[stock_ref]
        else:
            return None

    def __str__(self):
        if FashionShop.show_instrumentation:
            print('**Wywołano metodę __str__ klasy FashionShop')
        stock = map(str,self.__stock_dictionary.values())
        stock_list = '\n'.join(stock)
        template = '''Towary w magazynie

{0}
'''
        return template.format(stock_list)


# Utworzenie nowego obiektu FashionShop
shop=FashionShop()
# Zapisanie danych w pliku 
shop.save('FashionShop.pickle')

# Załadowanie kopii z pliku
loaded_shop = FashionShop.load('FashionShop.pickle')

# stworzenie nowego egzemplarza klasy Dress
dress = Dress(stock_ref='D001', price=100, color='czerwona', pattern='wieczorowa', size=12, location='przód')

# Zapis obiektu sukienki w obiekcie FashionShop
shop.store_new_stock_item(dress)

# Wyszukanie danych o sukience
item = shop.find_stock_item('D001')

#Wyświetlenie komunikatu o błędzie, jeśli sukienki nie znaleziono
if item == None:
    print('Nie znaleziono towaru')
else:
    print(item)

# Wyświetlenie całej zawartości sklepu z odzieżą
print(shop)
