from datetime import datetime
import math
import re


__authors__ = ["Ming Chen"]
__license__ = "Public Domain"
__maintainer__ = "Ming Chen"
__email__ = "ming.chen@noaa.gov"
__date__  = "April 5, 2026"

'''
#####################################################################
# 
# extract_att.py
#
# Purpose:
# This python script is used to extract the leo rinex data of a specific
# range of epoches from the input rinex v2 file and to generate a new rinex file
##
# History:  
#       Created by: Ming Chen 2026/04/05
#                   ming.chen@noaa.gov
# 
# Usage: 
#
#
#####################################################################

'''

def format_rinex_time(dt):
    """Format datetime into RINEX 2 time line (fixed width)"""
    return f"{dt.year:6d}{dt.month:6d}{dt.day:6d}{dt.hour:6d}{dt.minute:6d}{dt.second + dt.microsecond/1e6:13.7f}     GPS"


def parse_epoch_line(line):
    parts = line.split()

    year = int(parts[0])
    year += 2000 if year < 80 else 1900

    month = int(parts[1])
    day   = int(parts[2])
    hour  = int(parts[3])
    minute= int(parts[4])
    sec   = float(parts[5])

    sec_int = int(sec)
    micro = int((sec - sec_int) * 1e6)

    return datetime(year, month, day, hour, minute, sec_int, micro)


epoch_pattern = re.compile(
    r'^\s*(\d{2})\s+(\d{1,2})\s+(\d{1,2})\s+'
    r'(\d{1,2})\s+(\d{1,2})\s+(\d+\.\d+)\s+'
    r'(\d+)\s+(\d+)'
)

def parse_epoch_line_regex(line):
    match = epoch_pattern.match(line)
    if not match:
        return None

    year, month, day, hour, minute, sec, flag, nsat = match.groups()

    year = int(year)
    year += 2000 if year < 80 else 1900

    sec = float(sec)
    sec_int = int(sec)
    micro = int((sec - sec_int) * 1e6)

    dt = datetime(int(year), int(month), int(day),
                  int(hour), int(minute), sec_int, micro)

    return dt, int(nsat)

def extract_rinex_obs(input_file, output_file, start_time, end_time):

    with open(input_file, 'r') as f:
        lines = f.readlines()

    # ----------------------
    # 1. Separate header
    # ----------------------
    header = []
    i = 0
    while i < len(lines) and "END OF HEADER" not in lines[i]:    
        header.append(lines[i])
        i += 1
    header.append(lines[i])
    i += 1

    # ----------------------
    # 2. Get # of observables
    # ----------------------
    n_obs = 0
    for h in header:
        if "# / TYPES OF OBSERV" in h:
            n_obs = int(h[:6])
            break

    obs_lines_per_sat = math.ceil(n_obs / 5.0)

    # ----------------------
    # 3. Loop epochs
    # ----------------------
    selected_data = []
    selected_times = []
    while i < len(lines):

       line = lines[i]

       result = parse_epoch_line_regex(line)

       if result is None:
           i += 1
           continue

       epoch_time, nsat = result

       block_size = 1 + nsat * obs_lines_per_sat
       block = lines[i:i + block_size]

       if start_time <= epoch_time <= end_time:
           selected_data.extend(block)
           selected_times.append(epoch_time)

       i += block_size

    # ----------------------
    # 4. Update header times
    # ----------------------
    if selected_times:
        first_obs = min(selected_times)
        last_obs  = max(selected_times)

        new_header = []
        for h in header:
            if "TIME OF FIRST OBS" in h:
                new_line = f"{format_rinex_time(first_obs):<60}TIME OF FIRST OBS\n"
                new_header.append(new_line)
            elif "TIME OF LAST OBS" in h:
                new_line = f"{format_rinex_time(last_obs):<60}TIME OF LAST OBS\n"
                new_header.append(new_line)
            else:
                new_header.append(h)
    else:
        print("No data found in given time range.")
        return

    # ----------------------
    # 5. Write output
    # ----------------------
    with open(output_file, 'w') as f:
        f.writelines(new_header)
        f.writelines(selected_data)

    print(f"   Output written: {output_file}")
    print(f"   First epoch: {first_obs}")
    print(f"   Last  epoch: {last_obs}")






# ----------------------------------------------------------------------
# Argument parsing
# ----------------------------------------------------------------------
def parse_args():
    import argparse
    parser = argparse.ArgumentParser(
        description="Main Program arguments"
    )
   
    parser.add_argument("input", type=str,  help="RNX 2.0 input")
    parser.add_argument("output", type=str,  help="output")
    parser.add_argument("-start", "--start-time", type=str,  help="%Y%m%dT%H%M%S")
    parser.add_argument("-end", "--end-time", type=str,  help="%Y%m%dT%H%M%S")
    parser.add_argument("-v","--verbose", action='store_true',  help="print info for debug")


    return parser.parse_args()

    
if __name__ == "__main__":
     # python extract_rnx2.py /data2/mchen36/POD_DATA/cosmic2/LEOPOD/podRnx/2026.108/C211_20260418T083000.rnx test.out 
     #  -start 20260418T080000 -end 20260418T083000 
    args = parse_args()
    t_start = args.start_time
    t_end = args.end_time
    tstart = datetime.strptime(t_start, "%Y%m%dT%H%M%S")
    tend =  datetime.strptime(t_end, "%Y%m%dT%H%M%S")
    input_file = args.input ; output_file = args.output
    
    verbose = args.verbose

    print(tstart, tend)
    extract_rinex_obs(
    input_file, output_file,
    tstart, tend
     )
