# Derek Holloway 010396173

import datetime
import AssignmentData
import UI
from MyHashTable import DerekHashTable
from Truck import Truck
from DeliveryObject import deliveryStatus

def main():

    UserUI = UI.DataUI()                                    # Load in the UI library
    globalTime = datetime.time(8, 0)

    package_hash = DerekHashTable()                         # Init the hash table
    for pkg in AssignmentData.packages:                     # Load the packages into the hash table
        if "Delayed" in pkg.notes:
            pkg.status = deliveryStatus.IN_ROUTE_TO_HUB
        else:
            pkg.status = deliveryStatus.AT_THE_HUB
        package_hash.addItem(pkg.id, pkg)

    truck1 = Truck("1")                                     # Init truck 1 starting at 8:00
    truck1.startTime = datetime.time(8, 0)

    truck2 = Truck("2")                                     # Init truck 2 starting at 9:15 -> Delayed for package 6
    truck2.startTime = datetime.time(9, 5)

    truck3 = Truck("3")                                     # Init truck 3 starting as soon as the fastest truck returned
    truck3.startTime = None

    pauseTime = UserUI.TimePrompt(globalTime, truck1, truck2, truck3, package_hash) # start the first time prompt

    noRequirements = [1,2,4,5,7,8,10,11,12,17,21,22,23,24,26,27,29,30,31,33,34,35,37,39,40]
    truck2Only = [3,18,36,38]
    delayed = [6,9,25,28,32]
    sameTruck = [13,14,15,16,19,20]

    # Package requirements
    priority = [1,6,13,14,15,16,21,25,29,30,31,34,37,40]
    priority_hash = DerekHashTable()                        # Load the priority packages into a hash for quick lookup
    for cur in priority:
        priority_hash.addItem(cur, cur)

    # Sort the known packages
    t1_load = sameTruck                                     # Start with the packages that requrie the same truck
    t2_load = truck2Only + delayed                          # add in the truck 2 only and the delays
    t3_load = []                                            # create an empty list

    # Sort the Unknown packages
    for i, v in enumerate(noRequirements):                  # enumerate through all the packages not predefined
        if priority_hash.getItem(v):                        # if the item is a priority item
            if len(t1_load) < 16:                           # load priorities on truck 1 first as it leaves earlier
                t1_load.append(v)
            elif len(t2_load) < 16:                         # fallback to truck 2
                t2_load.append(v)
            else:                                           # fallback again to truck 3
                t3_load.append(v)
        else:
            if len(t3_load) < 16:                           # non priority pkgs default to truck 3 as it leaves last
                t3_load.append(v)
            elif len(t2_load) < 16:                         # fall back to truck 2
                t2_load.append(v)
            elif len(t1_load) < 16:                         # fallback again to truck 1
                t1_load.append(v)

    # Run the simulation until all the packages have been delivered
    debounce1 = True
    debounce2 = True
    debounce3 = True
    truck3LoadDebounce = True
    arrivalDebounce = True
    while True:

        # check if packages have arrived to the hub
        if arrivalDebounce and globalTime >= datetime.time(9, 5):
            arrivalDebounce = False
            for v in package_hash:
                if v.status == deliveryStatus.IN_ROUTE_TO_HUB:
                    v.status = deliveryStatus.AT_THE_HUB

        # check for pause time
        if globalTime >= pauseTime:
            pauseTime = UserUI.TimePrompt(globalTime, truck1, truck2, truck3, package_hash)

        # update global time
        if globalTime >= datetime.time(10, 20):                     # If the time is correct for update
            pkg9 = package_hash.getItem(9)                          # Handle the Package #9 address correction before Truck 3 starts
            pkg9.address = "410 S State St"

        # load packages for truck 1
        if globalTime >= truck1.startTime and debounce1:            # If its time to laod the packages, run once
            debounce1 = False                                       # set debounce for only one run
            truck1.hasLoad = True                                   # Set the truck load variable
            for pkg_id in t1_load:                                  # Load the packages in truck 1
                truck1.addPkg(package_hash.getItem(pkg_id))

        # load packages for truck 2
        if globalTime >= truck2.startTime and debounce2:            # If its time to laod the packages, run once
            debounce2 = False                                       # set debounce for only one run
            truck2.hasLoad = True                                   # Set the truck load variable
            for pkg_id in t2_load:                                  # Load the packages in truck 2
                truck2.addPkg(package_hash.getItem(pkg_id))

        # load packages for truck 3
        if type(truck3.startTime) is datetime.time:                 # Verify type corectness
            if globalTime >= truck3.startTime and debounce3:        # If its time to laod the packages, run once
                debounce3 = False                                   # set debounce for only one run
                truck3.hasLoad = True                               # Set the truck load variable
                for pkg_id in t3_load:                              # Load the packages in truck 2
                    truck3.addPkg(package_hash.getItem(pkg_id))

        # deliver packages for truck 1
        if truck1.hasLoad and globalTime >= truck1.getTimeOfDay():  # if there is more packages and the time has passed
            truck1.driveNextClosest(priority_hash)                  # deliver the next set of packages
            if len(truck1.packages) == 0 and truck3LoadDebounce:    # if all the packages are delivered
                truck1.driveNextClosest(priority_hash)              # drive back to the HUB
                truck3LoadDebounce = False                          # set the debouce
                truck3.startTime = truck1.getTimeOfDay()            # set truck3 start time

        # deliver packages for truck 2
        if truck2.hasLoad and globalTime >= truck2.getTimeOfDay():  # if there is more packages and the time has passed
            truck2.driveNextClosest(priority_hash)                  # deliver the next set of packages
            if len(truck2.packages) == 0 and truck3LoadDebounce:    # if all the packages are delivered
                truck2.driveNextClosest(priority_hash)              # drive back to the HUB
                truck3LoadDebounce = False                          # set the debouce
                truck3.startTime = truck1.getTimeOfDay()            # set truck3 start time

        # deliver packages for truck 3
        if truck3.hasLoad and globalTime >= truck3.getTimeOfDay():  # if there is more packages and the time has passed
            truck3.driveNextClosest(priority_hash)                  # deliver the next set of packages

        # Calculate new global time
        totalMins = (globalTime.hour * 60) + globalTime.minute + 5  # Get total mins and add 30
        offsetHour = (totalMins // 60) % 24                         # pull hours back out
        offsetMins = totalMins % 60                                 # pull minutes back out
        globalTime = datetime.time(offsetHour, offsetMins)          # return the time of day

        # if we are done delivering
        if (truck3.hasLoad == False and truck2.hasLoad == False and truck1.hasLoad == False):
            break

    UserUI.MainSelectionPrompt(truck1, truck2, truck3, package_hash)    # Display the command prompt Menus

if __name__ == "__main__":
    main()