import dateutil.relativedelta as tdelta
from datetime import datetime, timezone
from mpl_toolkits.basemap import Basemap


class Trip(object):
    """
    Trip objects are generated by the controller when it
    discovers that trips are taking place during the current time step and added
    to that minute's *render*
    """
    start_time = None
    end_time = None
    start_st = 0
    start_coords = ()  # float tuples loaded in at init
    end_coords = ()
    end_st = 0
    trip_length = 0
    length_mins = 0
    minutes_done = 0

    # store n (length_mins) computed GC interpolated points for later retrieval
    gcpoints = ()

    def __init__(self, sta_dict, m, start_time, end_time, start_st, end_st):
        self.start_time = start_time
        self.end_time = end_time
        self.start_st = start_st    # start station
        self.end_st = end_st    # end station id

        # TODO protect against bad keys here
        self.start_coords = (float(sta_dict[self.start_st][4]),
                             float(sta_dict[self.start_st][3]))
        self.end_coords = (float(sta_dict[self.end_st][4]),
                           float(sta_dict[self.end_st][3]))
        self.trip_length = tdelta.relativedelta(end_time, start_time)
        self.length_mins = self.trip_length.minutes

        # For the too-long trips
        if self.trip_length.days > 0:
            self.length_mins += 24 * 60 * self.trip_length.days
        if self.trip_length.hours > 0:
            self.length_mins += 60 * self.trip_length.hours

        self.minutes_done = 0    # total minutes elapsed
        self.percent_done = 0.0  # currently unused stub for a state-based setup
        
        try:
            self.gcpoints = m.gcpoints(
                self.start_coords[0], self.start_coords[1], self.end_coords[0], self.end_coords[1], self.length_mins)
        except ZeroDivisionError as e:
            print("ZDE: ", e, self.length_mins)
            raise

        init_str = "[init] Trip w/ start: {0}, end: {1} with duration {2} mins".format(
            start_st, end_st, self.length_mins)
        print(init_str)

    def calc_pos(self, current_time):
        """
        Void function calculates gcpoints with n (minutes) points if not 
        already loaded in object and returns the "current" point
        """
        x = tdelta.relativedelta(current_time, self.start_time)
        xmins = x.minutes
        if x.hours > 0:
            xmins += x.hours * 60
        if (xmins == self.length_mins):    # block index erroring in few cases
            xmins -= 1

        return (self.gcpoints[0][xmins], self.gcpoints[1][xmins])

    def __str__(self):
        """
        toString for debugging
        """
        id_str = "Trip [{0}] ".format(id(self))
        start_str = "Started {0} at {1}".format(
            str(self.start_time), self.start_st)
        end_str = " | Ended {0} at {1}\n".format(
            str(self.end_time), self.end_st)
        return ''.join([id_str, start_str, end_str])
