import math


def read_file(input_file: str) -> dict:
    """
    Read the file and extract relevant data

    Parameters
    ----------
    input_file : string
        HiTrack filename

    Returns
    -------
    data: dict of lists of lists
        {'gps': list of lists, 'alti': list of lists, 'hr': list of lists, 'cad': list of lists}
    """

    def _normalize_timestamp(timestamp: float) -> float:
        """ Normalize the timestamp

        Timestamps taken from different devices can have different values. Most common are seconds
        (i.e. t=1.543646826E9) or microseconds (i.e. t=1.55173212E12).
        This method implements a generic normalization function that transform all values to valid
        unix timestamps (integer with 10 digits).
        """
        oom = int(math.log10(timestamp))
        if oom == 9:
            return timestamp

        divisor = 10 ** (oom - 9) if oom > 9 else 0.1 ** (9 - oom)
        return timestamp / divisor

    print('---- Input File ----')
    print('reading: ', end='')
    try:
        """ The lap list will contain lap data will contain start-stop times between pauzes identified in 
            the location records. These are required to generate the laps in the output TCX file later.
        """
        data = {'gps': [], 'alti': [], 'hr': [], 'cad': [], 'lap': []}
        with open(input_file) as f:
            lap_start_stop = []
            lap_start_stop.append(0)  # Start time of lap
            lap_start_stop.append(0)  # Stop time of lap

            for line in f:
                # Loop over file line by line
                holding_list = []

                if line[0:6] == 'tp=lbs': # Location lines
                    for x in [6,3,4,0,0,0,0]: # time, lat, long, [alti], [dist], [hr], [cad]
                        if x == 0:
                            holding_list.append('') # Fill in blanks with blank
                        else:
                            holding_list.append(float(line.split('=')[x].split(';')[0]))
                    """ Do not try to normalize time for 'Pauze' records.
                         E.g. tp=lbs;k=<a number>;lat=90.0;lon=-80.0;alt=0.0;t=0.0;
                         Recognized by time = 0, lat = 90, long = -80
                    """
                    if holding_list[0] != 0 and holding_list[1] != 90 and holding_list[2] != -80:
                        holding_list[0] = _normalize_timestamp(holding_list[0])
                        data['gps'].append(holding_list)
                        if lap_start_stop[0] == 0:
                            # First valid time for new lap. Store it in start time (index 0).
                            lap_start_stop[0] = holding_list[0]
                        if lap_start_stop[1] < holding_list[0]:
                            # Later stop time for current lap. Store it in stop time (index 1).
                            lap_start_stop[1] = holding_list[0]
                    else:
                        """ Pauze record detected.
                             E.g. tp=lbs;k=<a number>;lat=90.0;lon=-80.0;alt=0.0;t=0.0;
                             Recognized by time = 0, lat = 90, long = -80
                             Add the record to the gps data list. When generating the TCX XML this record can be
                             used to create a new 'lap' with start time the time of the next record (if any, e.g.
                             when workout was first pauzed and then stopped without resuming.)
                             Store lap record in data and create a new one. 
                        """
                        data['lap'].append(lap_start_stop)
                        lap_start_stop = []
                        lap_start_stop.append(0)
                        lap_start_stop.append(0)

                elif line[0:6] == 'tp=h-r': # Heart-rate lines
                    for x in [2,0,0,0,0,3,0]: #time, [lat], [long], [alti], [dist], hr, [cad]
                        if x == 0:
                            holding_list.append('')
                        elif x == 2:
                            holding_list.append(int(float(line.split('=')[x].split(';')[0])))
                        else:
                            holding_list.append(int(line.split('=')[x].split(';')[0]))
                    holding_list[0] = _normalize_timestamp(holding_list[0])
                    data['hr'].append(holding_list)

                elif line[0:6] == 'tp=s-r': # Cadence lines
                    for x in [2,0,0,0,0,0,3]: #time, [lat], [long], [alti], [dist], [hr], cad
                        if x == 0:
                            holding_list.append('')
                        elif x == 2:
                            holding_list.append(int(float(line.split('=')[x].split(';')[0])))
                        else:
                            holding_list.append(int(line.split('=')[x].split(';')[0]))
                    holding_list[0] = _normalize_timestamp(holding_list[0])
                    data['cad'].append(holding_list)

                elif line[0:7] == 'tp=alti': # Altitude lines
                    for x in [2,0,0,3,0,0,0]: #time, [lat], [long], alti, [dist], [hr], [cad]
                        if x == 0:
                            holding_list.append('')
                        elif x == 2:
                            holding_list.append(int(float(line.split('=')[x].split(';')[0])))
                        else:
                            holding_list.append(float(line.split('=')[x].split(';')[0]))
                    holding_list[0] = _normalize_timestamp(holding_list[0])
                    data['alti'].append(holding_list)

        """ Save (last) lap data. When the exercise wasn't pauzed and/or no pauze/stop record is generated as the last
            location record, store the single lap record here.
        """
        if lap_start_stop[0] != 0:
            data['lap'].append(lap_start_stop)

        # Sort GPS data by date for distance computation
        data['gps'] = sorted(data['gps'], key=lambda x : x[0])

    except:
        print('FAILED')
        exit()

    print('OKAY')
    return data