def solution_firstAvailableElf(toy_file, soln_file):
    """ Creates a simple solution where the next available elf is assigned a toy. Elves do not start
    work outside of sanctioned hours.
    :param toy_file: filename for toys file (input)
    :param soln_file: filename for solution file (output)
    :param my_elves: list of elves in a priority queue ordered by next available time
    :return:
    """
    hrs = Hours()
    ref_time = datetime.datetime(2014, 1, 1, 0, 0)
    row_count = 0
    toy_list = []

    my_elves = create_elves(NUM_ELVES)

    #Build list of toys
    with open(toy_file, 'rb') as f:
        toysfile = csv.reader(f)
        toysfile.next()  # header row
        for row in toysfile:
            current_toy = Toy(row[0], row[1], row[2])
            toy_list.append(current_toy)

    big_toys = sorted([x for x in toy_list if x.duration > 600], key = lambda e: -e.duration)
    small_toys = sorted([x for x in toy_list if x.duration <= 600], key = lambda e: e.duration)

    toy_list = None
    gc.collect()

    sorted_toy_list = big_toys + small_toys

    big_toys = small_toys = None
    gc.collect()

    with open(soln_file, 'wb') as w:
        wcsv = csv.writer(w)
        wcsv.writerow(['ToyId', 'ElfId', 'StartTime', 'Duration'])
        while len(sorted_toy_list) > 0:
            elf_available_time, current_elf = heapq.heappop(my_elves)
            if current_elf.rating > 3:
                current_toy = sorted_toy_list.pop()
            else:
                val = hrs.get_sanctioned_time_left(elf_available_time)
                current_toy_idx = find_closest_idx(sorted_toy_list, current_elf.rating * (val*1.025))
                current_toy = sorted_toy_list.pop(current_toy_idx)

            if len(sorted_toy_list) % 1000 == 0:
                print "[Elf %s @ %0.2f] => toy %s @ %s -- %0.2f%% done" % (current_elf.id, current_elf.rating, current_toy.id, current_toy.duration, len(sorted_toy_list) / 10000.0)

            # get next available elf

            work_start_time = elf_available_time

            #!# work_start_time cannot be before toy's arrival
            #!if work_start_time < current_toy.arrival_minute:
            #!    print 'Work_start_time before arrival minute: {0}, {1}'.\
            #!        format(work_start_time, current_toy.arrival_minute)
            #!    exit(-1)

            current_elf.next_available_time, work_duration = assign_elf_to_toy(work_start_time, current_elf, current_toy, hrs)
            current_elf.update_elf(hrs, current_toy, work_start_time, work_duration)

            # put elf back in heap
            heapq.heappush(my_elves, (current_elf.next_available_time, current_elf))

            # write to file in correct format
            tt = ref_time + datetime.timedelta(seconds=60*work_start_time)
            time_string = " ".join([str(tt.year), str(tt.month), str(tt.day), str(tt.hour), str(tt.minute)])
            wcsv.writerow([current_toy.id, current_elf.id, time_string, work_duration])
def solution_firstAvailableElf(toy_file, soln_file, myelves):
    """ Creates a simple solution where the next available elf is assigned a toy. Elves do not start
    work outside of sanctioned hours.
    :param toy_file: filename for toys file (input)
    :param soln_file: filename for solution file (output)
    :param myelves: list of elves in a priority queue ordered by next available time
    :return:
    """
    hrs = Hours()
    ref_time = datetime.datetime(2014, 1, 1, 0, 0)
    row_count = 0
    toy_list = []
    loop_count = 0

    #Build list of toys
    with open(toy_file, 'rb') as f:
        toysfile = csv.reader(f)
        toysfile.next()  # header row
        for row in toysfile:
            current_toy = Toy(row[0], row[1], row[2])
            toy_list.append(current_toy)

    sorted_toy_list = sorted(toy_list,key = lambda e: e.duration)
    toy_list = None
    gc.collect()

    print 'All is sorted:'

    with open(soln_file, 'wb') as w:
        wcsv = csv.writer(w)
        wcsv.writerow(['ToyId', 'ElfId', 'StartTime', 'Duration'])
        while len(sorted_toy_list) > 0:
            elf_available_time, current_elf = heapq.heappop(myelves)
            if current_elf.rating > 3.9:
                current_toy = sorted_toy_list.pop()
                print 'Elf {0} eff {1} toy {2} duration {3} BIG TOY---------------------------------'.format(current_elf.id, current_elf.rating, current_toy.id, current_toy.duration)
                loop_count = loop_count + 1
            else:
                val = hrs.get_sanctioned_time_left(elf_available_time)
                current_toy_idx = find_closest_idx(sorted_toy_list, current_elf.rating * (val*1.15))
                current_toy = sorted_toy_list.pop(current_toy_idx)
                if len(sorted_toy_list) % 10 == 0:
                    print 'Elf {0} eff {1} toy {2} duration {3} SMALL TOY {4}> {5}'.format(current_elf.id, current_elf.rating, current_toy.id, current_toy.duration, len(sorted_toy_list), len(sorted_toy_list))

            # get next available elf

            work_start_time = elf_available_time

            #!# work_start_time cannot be before toy's arrival
            #!if work_start_time < current_toy.arrival_minute:
            #!    print 'Work_start_time before arrival minute: {0}, {1}'.\
            #!        format(work_start_time, current_toy.arrival_minute)
            #!    exit(-1)

            current_elf.next_available_time, work_duration = \
                assign_elf_to_toy(work_start_time, current_elf, current_toy, hrs)
            current_elf.update_elf(hrs, current_toy, work_start_time, work_duration)

            # put elf back in heap
            heapq.heappush(myelves, (current_elf.next_available_time, current_elf))

            # write to file in correct format
            tt = ref_time + datetime.timedelta(seconds=60*work_start_time)
            time_string = " ".join([str(tt.year), str(tt.month), str(tt.day), str(tt.hour), str(tt.minute)])
            wcsv.writerow([current_toy.id, current_elf.id, time_string, work_duration])
    print 'loop_count = {0}'.format(loop_count)