# Student ID: 012498637
# Student Name: Zakaria Benmoulay
# Course: C950 - Data Structures and Algorithms II


class ChainingHashTable:

    # We are going to assigns all buckets with an empty list.
    def __init__(self, initial_capacity=40):
        # Let's initialize the hash table with empty bucket list entries.
        self.table = []
        for i in range(initial_capacity):
            self.table.append([])

    # This func inserts a new item into the hash table.
    def insert(self, key, item):
        # Get the bucket list where this item will go.
        bucket = hash(key) % len(self.table)
        bucket_list = self.table[bucket]

        # Let's check if the key already exists and update it if found.
        for kv in bucket_list:
            if kv[0] == key:
                kv[1] = item
                return True

        # otherwise, we insert the item to the end of list.
        key_value = [key, item]
        bucket_list.append(key_value)
        return True

    # This func returns the item if found, or None if not found.
    def lookup(self, key):
        # Let's find the correct bucket for this key.
        bucket = hash(key) % len(self.table)
        bucket_list = self.table[bucket]

        # Let's search through the bucket for the matching key.
        for kv in bucket_list:
            if kv[0] == key:
                return kv[1]
        return None

    # This func removes an item with matching key from the hash table.
    def remove(self, key):
        # Let's find the bucket where this key should exist.
        bucket = hash(key) % len(self.table)
        bucket_list = self.table[bucket]

        # Let's search for and remove the matching key-value pair.
        for kv in bucket_list:
            if kv[0] == key:
                bucket_list.remove([kv[0], kv[1]])
                return print('Package ', key, 'successfully deleted.')

        # Let's return None if the key is not found.
        return None

    # This func returns a list of all (key, value) tuples stored in the hash table.
    # Let's use this to iterate through all packages when needed.
    def get_all(self):
        result = []
        for bucket_list in self.table:
            for kv in bucket_list:
                result.append((kv[0], kv[1]))
        return result