from unittest import TestCase
from quetzal import *

def get_list_of_stock(stock_list):
    dates = []
    for i in range(1, len(stock_list)):
        dates.append(stock_list[i].get_expiration_date())
    return dates

class TestStock(TestCase):

    def test_empty(self):
        s = Stock(["wit", "zwart", "bruin"], AdtCircularLinkedList)
        self.assertTrue(s.is_empty("wit"))
        self.assertTrue(s.is_empty("zwart"))
        self.assertTrue(s.is_empty("bruin"))
        self.assertTrue(s.is_empty("honing"))
        self.assertEqual(0, s.get_size("wit"))
        self.assertEqual(0, s.get_size("bruin"))
        self.assertEqual(0, s.get_size("zwart"))
        self.assertEqual(0, s.get_size("honing"))
        self.assertEqual(["wit", "zwart", "bruin"], s.get_product_list())

    def test_add_items(self):
        s = Stock(["shot wit", "shot zwart", "shot bruin"], AdtCircularLinkedList)
        self.assertTrue(s.add_item(Chocolateshot(Date(2020, 10, 2), "wit")))
        self.assertFalse(s.is_empty("shot wit"))
        self.assertTrue(s.is_empty("shot zwart"))
        self.assertTrue(s.is_empty("shot bruin"))
        self.assertTrue(s.add_item(Chocolateshot(Date(2020, 9, 13), "wit")))
        self.assertTrue(s.add_item(Chocolateshot(Date(2019, 7, 2), "wit")))
        self.assertTrue(s.add_item(Chocolateshot(Date(2019, 10, 2), "zwart")))
        self.assertTrue(s.add_item(Chocolateshot(Date(2019, 10, 2), "zwart")))
        self.assertTrue(s.add_item(Chocolateshot(Date(2020, 7, 21), "zwart")))
        self.assertTrue(s.add_item(Chocolateshot(Date(2020, 6, 22), "zwart")))
        self.assertTrue(s.add_item(Chocolateshot(Date(2016, 5, 2), "bruin")))
        self.assertFalse(s.is_empty("shot zwart"))
        self.assertFalse(s.is_empty("shot bruin"))
        self.assertEqual(3, s.get_size("shot wit"))
        self.assertEqual(4, s.get_size("shot zwart"))
        self.assertEqual(1, s.get_size("shot bruin"))
        with self.assertRaises(KeyError):
            s.add_item(Marshmallow(Date(2018, 1, 1)))
        with self.assertRaises(KeyError):
            s.add_item(Chocolateshot(Date(2018, 1, 1), "melk"))
        self.assertTrue(s.is_empty("marshmallow"))
        self.assertTrue(s.is_empty("melk"))

    def test_clean_stock_2(self):
        s = Stock(["honing", "chili", "marshmallow","shot wit", "shot zwart", "shot bruin"], AdtCircularLinkedList)
        self.assertEqual(["honing", "chili", "marshmallow","shot wit", "shot zwart", "shot bruin"], s.get_product_list())
        for i in range(2,30,3):
            self.assertTrue(s.add_item(Chilipepper(Date(2018, 9, i))))
            self.assertTrue(s.add_item(Chocolateshot(Date(2018, 10, i), "wit")))
            self.assertTrue(s.add_item(Marshmallow(Date(2018, 10, i))))
            self.assertTrue(s.add_item(Chocolateshot(Date(2018, 10, i), "zwart")))
            self.assertTrue(s.add_item(Honey(Date(2018, 12, i))))
        self.assertEqual(10, s.get_size("shot wit"))
        self.assertEqual(10, s.get_size("honing"))
        self.assertEqual(10, s.get_size("marshmallow"))
        self.assertEqual(10, s.get_size("chili"))
        self.assertEqual(10, s.get_size("shot zwart"))
        self.assertEqual(0, s.get_size("snoep"))
        self.assertEqual(28, len(s.clean_stock(Date(2018, 10, 20))))
        self.assertEqual(0, s.get_size("chili"))
        self.assertEqual(4, s.get_size("shot wit"))
        self.assertEqual(4, s.get_size("shot zwart"))
        self.assertEqual(10, s.get_size("honing"))
        self.assertEqual(4, s.get_size("marshmallow"))

    def test_clean_stock_3(self):
        s = Stock(["honing", "chili", "marshmallow", "shot wit", "shot zwart", "shot bruin"], AdtCircularLinkedList)
        self.assertEqual(["honing", "chili", "marshmallow", "shot wit", "shot zwart", "shot bruin"], s.get_product_list())
        for i in range(2,30,3):
            self.assertTrue(s.add_item(Chilipepper(i-20)))
            self.assertTrue(s.add_item(Chocolateshot(i, "wit")))
            self.assertTrue(s.add_item(Marshmallow(i)))
            self.assertTrue(s.add_item(Chocolateshot(i, "zwart")))
            self.assertTrue(s.add_item(Honey(i+100)))
        self.assertEqual(10, s.get_size("shot wit"))
        self.assertEqual(10, s.get_size("honing"))
        self.assertEqual(10, s.get_size("marshmallow"))
        self.assertEqual(0, s.get_size("shot bruin"))
        self.assertEqual(0, s.get_size("snoep"))
        s.clean_stock(20)
        self.assertEqual(0, s.get_size("chili"))
        self.assertEqual(4, s.get_size("shot wit"))
        self.assertEqual(10, s.get_size("honing"))
        self.assertEqual(4, s.get_size("marshmallow"))
        self.assertTrue(s.is_empty("shot bruin"))

    def test_pop_items(self):
        s = Stock(["honing", "chili", "marshmallow", "shot wit", "shot zwart", "shot bruin"], AdtCircularLinkedList)
        self.assertEqual(["honing", "chili", "marshmallow", "shot wit", "shot zwart", "shot bruin"], s.get_product_list())
        for i in range(2, 30, 3):
            self.assertTrue(s.add_item(Chilipepper(Date(2018, 9, i))))
            self.assertTrue(s.add_item(Chocolateshot(Date(2018, 10, i), "wit")))
            self.assertTrue(s.add_item(Marshmallow(Date(2018, 10, i))))
            self.assertTrue(s.add_item(Chocolateshot(Date(2018, 10, i), "zwart")))
            self.assertTrue(s.add_item(Honey(Date(2018, 12, i))))
        self.assertEqual(28, len(s.clean_stock(Date(2018, 10, 20))))
        self.assertEqual(None, s.pop_item("bruin", Date(2017, 10, 20)))
        self.assertEqual(None, s.pop_item("wit", Date(2020, 2, 2)))
        self.assertEqual(Date(2018, 10, 20), s.pop_item("marshmallow", Date(2017, 10, 20)).get_expiration_date())
        self.assertEqual(Date(2018, 10, 23), s.pop_item("marshmallow", Date(2017, 10, 20)).get_expiration_date())
        self.assertEqual(2, s.get_size("marshmallow"))
        self.assertEqual(Date(2018, 10, 26), s.pop_item("marshmallow", Date(2017, 10, 20)).get_expiration_date())
        self.assertEqual(Date(2018, 10, 29), s.pop_item("marshmallow", Date(2017, 10, 20)).get_expiration_date())
        self.assertTrue(s.is_empty("marshmallow"))
        self.assertEqual(None, s.pop_item("marshmallow", Date(2017, 10, 20)))
        self.assertEqual(None, s.pop_item("honing", Date(2021, 1, 1)))
        self.assertEqual("honing", s.pop_item("honing", Date(2018, 1, 1)).get_name())
        self.assertEqual(Date(2018, 12, 5), s.pop_item("honing", Date(2018, 1, 1)).get_expiration_date())
        self.assertEqual(Date(2018, 12, 20), s.pop_item("honing", Date(2018, 12, 19)).get_expiration_date())
        self.assertEqual(7, s.get_size("honing"))
        self.assertTrue(s.add_item(Marshmallow(Date(2019, 1, 1))))
        self.assertFalse(s.is_empty("marshmallow"))
        self.assertEqual(1, s.get_size("marshmallow"))
        self.assertEqual(["honing", "chili", "marshmallow", "shot wit", "shot zwart", "shot bruin"], s.get_product_list())

    def test_sort(self):
        s = Stock(["honing"], AdtCircularLinkedList)
        self.assertTrue(s.add_item(Honey(Date(2018, 12, 1))))
        self.assertTrue(s.add_item(Honey(Date(2017, 1, 1))))
        self.assertTrue(s.add_item(Honey(Date(2018, 6, 1))))
        self.assertTrue(s.add_item(Honey(Date(2017, 1, 1))))
        self.assertTrue(s.add_item(Honey(Date(2018, 12, 20))))
        self.assertTrue(s.add_item(Honey(Date(2018, 8, 1))))
        self.assertTrue(s.add_item(Honey(Date(2017, 12, 1))))
        self.assertTrue(s.add_item(Honey(Date(2017, 8, 1))))
        self.assertEqual(8, s.get_size("honing"))
        self.assertEqual(Date(2018, 12, 1), s.stocks[0][1].get_expiration_date())
        self.assertEqual(Date(2017, 1, 1), s.stocks[0][2].get_expiration_date())
        self.assertEqual(Date(2018, 6, 1), s.stocks[0][3].get_expiration_date())
        self.assertEqual(Date(2017, 1, 1), s.stocks[0][4].get_expiration_date())
        self.assertEqual(Date(2018, 12, 20), s.stocks[0][5].get_expiration_date())
        self.assertEqual(Date(2018, 8, 1), s.stocks[0][6].get_expiration_date())
        self.assertEqual(Date(2017, 12, 1), s.stocks[0][7].get_expiration_date())
        self.assertEqual(Date(2017, 8, 1), s.stocks[0][8].get_expiration_date())
        for stock_list in s.stocks:
            s._sort(stock_list)
        self.assertEqual(8, s.get_size("honing"))
        self.assertEqual(Date(2017, 1, 1), s.stocks[0][1].get_expiration_date())
        self.assertEqual(Date(2017, 1, 1), s.stocks[0][2].get_expiration_date())
        self.assertEqual(Date(2017, 8, 1), s.stocks[0][3].get_expiration_date())
        self.assertEqual(Date(2017, 12, 1), s.stocks[0][4].get_expiration_date())
        self.assertEqual(Date(2018, 6, 1), s.stocks[0][5].get_expiration_date())
        self.assertEqual(Date(2018, 8, 1), s.stocks[0][6].get_expiration_date())
        self.assertEqual(Date(2018, 12, 1), s.stocks[0][7].get_expiration_date())
        self.assertEqual(Date(2018, 12, 20), s.stocks[0][8].get_expiration_date())

    def test_empty_before_adding(self, type = AdtCircularLinkedList):
        stock = Stock(["honing", "chilipeper", "marshmallow", "wit", "zwart", "melk"], type)
        self.assertTrue(stock.is_empty("chilipeper"))
        self.assertTrue(stock.is_empty("honing"))
        self.assertTrue(stock.is_empty("wit"))
        self.assertTrue(stock.is_empty("melk"))
        self.assertTrue(stock.is_empty("bruin"))
        self.assertTrue(stock.is_empty("zwart"))
        self.assertTrue(stock.is_empty("marshmallow"))
        self.assertTrue(stock.is_empty("snoep"))

    def test_empty_after_adding(self, type = AdtCircularLinkedList):
        stock = Stock(["honing", "chili", "marshmallow", "shot wit", "shot bruin", "shot zwart", "shot melk"], type)
        stock.add_item(Chocolateshot(2, "wit"))
        stock.add_item(Chocolateshot(2, "wit"))
        stock.add_item(Marshmallow(3))
        stock.add_item(Honey(2))
        stock.add_item(Chilipepper(12))
        stock.add_item(Chocolateshot(52, "bruin"))
        stock.add_item(Chocolateshot(753, "melk"))

        self.assertFalse(stock.is_empty("chili"))
        self.assertFalse(stock.is_empty("honing"))
        self.assertFalse(stock.is_empty("shot wit"))
        self.assertFalse(stock.is_empty("shot melk"))
        self.assertFalse(stock.is_empty("shot bruin"))
        self.assertFalse(stock.is_empty("marshmallow"))

    def test_add_and_pop(self, type = AdtCircularLinkedList):
        stock = Stock(["honing", "chili", "marshmallow", "wit", "bruin", "zwart", "melk"], type)
        stock.add_item(Honey(2))
        stock.add_item(Honey(4))
        stock.add_item(Honey(10))
        stock.add_item(Honey(3))
        self.assertEqual([2, 4, 10, 3], get_list_of_stock(stock.stocks[0]))
        stock.add_item(Chilipepper(3))
        stock.add_item(Chilipepper(4))
        stock.add_item(Chilipepper(12))
        stock.add_item(Chilipepper(5))
        self.assertEqual([3, 4, 12, 5], get_list_of_stock(stock.stocks[1]))
        stock.pop_item('honing', 4)
        self.assertEqual([2, 3, 10], get_list_of_stock(stock.stocks[0]))

        stock.pop_item('chili', 3)
        self.assertEqual([4, 5, 12], get_list_of_stock(stock.stocks[1]))

        stock.add_item(Chilipepper(8))
        stock.add_item(Chilipepper(13))
        stock.add_item(Chilipepper(35))
        stock.add_item(Chilipepper(1))
        stock.pop_item('chili', 10)
        self.assertEqual([1, 4, 5, 8, 13, 35], get_list_of_stock(stock.stocks[1]))

    def test_clean_stock(self, type = AdtCircularLinkedList):
        stock = Stock(["honing", "chili", "marshmallow", "shot wit", "shot bruin", "shot zwart", "shot melk"], type)
        stock.add_item(Chilipepper(1))
        stock.add_item(Chilipepper(10))
        stock.add_item(Chilipepper(12))
        stock.add_item(Chilipepper(78))
        ##
        stock.add_item(Honey(13))
        stock.add_item(Honey(23))
        stock.add_item(Honey(4))
        stock.add_item(Honey(18))
        ##
        stock.add_item(Marshmallow(16))
        stock.add_item(Marshmallow(21))
        stock.add_item(Marshmallow(32))
        stock.add_item(Marshmallow(11))
        ##
        stock.add_item(Chocolateshot(8, "bruin"))
        stock.add_item(Chocolateshot(9, "bruin"))
        stock.add_item(Chocolateshot(10, "bruin"))
        stock.add_item(Chocolateshot(11, "bruin"))
        ##
        stock.add_item(Chocolateshot(11, "wit"))
        stock.add_item(Chocolateshot(10, "wit"))
        stock.add_item(Chocolateshot(9, "wit"))
        stock.add_item(Chocolateshot(8, "wit"))
        ##
        stock.add_item(Chocolateshot(54, "melk"))
        stock.add_item(Chocolateshot(54, "melk"))
        stock.add_item(Chocolateshot(1, "melk"))
        stock.add_item(Chocolateshot(54, "melk"))
        ##
        stock.clean_stock(10)

        self.assertEqual([10, 12, 78], get_list_of_stock(stock.stocks[1]))
        self.assertEqual([13, 18, 23], get_list_of_stock(stock.stocks[0]))
        self.assertEqual([11, 16, 21, 32], get_list_of_stock(stock.stocks[2]))
        self.assertEqual([10, 11], get_list_of_stock(stock.stocks[4]))
        self.assertEqual([10, 11], get_list_of_stock(stock.stocks[3]))
        self.assertEqual([54, 54, 54], get_list_of_stock(stock.stocks[6]))
