import argparse
import subprocess
import os
import glob
import logging
import sys
import time


def main():
    parser = argparse.ArgumentParser(
        description='Process long runs of T04 data, where mutiple (livesky) '
        'T04 files need to be combined, and then differenced. Attempt to '
        'only run the necessary processes to create any data files '
        'missing in the data pipeline.',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
        )
    parser.add_argument(
        "-F", "--folder",
        type=str,
        default='.',
        help="Root folder",
        )
    parser.add_argument(
        "-d", "--days",
        type=str,
        nargs='+',
        default=None,
        help="List of days directories"
             "Example: -d 0115 0116",
        )
    parser.add_argument(
        "-D", "--devs",
        type=str,
        nargs='+',
        default = [
            'WCO-Base',
            #'WCO-Base', 'BXLVL', 'JudoRoof', 'survey-base',    # Bases
            #'MS956', 'P4-03', 'P4-05',                         # DUTs
            ],
        help="List of dev directories, that will be inside the days dirs"
             "Example: -D BXLVL JudoRoof",
        )
    parser.add_argument(
        "-e", "--elevation",
        type=float,
        default=10,
        help="Set elevation mask."
        )
    parser.add_argument(
        "--t0x2t0x",
        default='t0x2t0x',
        help="Executable name for t0x2t0x."
        )
    parser.add_argument(
        '-n', "--dryrun",
        action="store_true",
        help="Don't actually run t0x2t0x."
        )
    parser.add_argument(
        "--log_dir", default="logs",
        help="Where to store .log files"
        )
    parser.add_argument(
        '--parallel',
        action=argparse.BooleanOptionalAction,
        default=False,
        help="Run each process in parallel",
        )
    parser.add_argument('-v', '--verbose', action='count', default=0)

    args = parser.parse_args()
    logger_format = ("[%(levelname)-8s]"
                     "[%(filename)11s:%(lineno)-5s] "
                     "%(funcName)-10s: %(message)s"
                     )
    logging.basicConfig(
        level=logging.WARNING - (10 * args.verbose),
        format=logger_format,
        stream=sys.stdout
    )

    os.makedirs(args.log_dir, exist_ok=True)

    if args.days is None:
        days = []
        with os.scandir(args.folder) as it:
            for entry in it:
                d = entry.name
                if not entry.is_dir() or d.startswith('_') or d.startswith('.'):
                    continue
                if d == 'figures' or d == 'logs':
                    continue
                days.append(d)
        days.sort()
    else:
        days = args.days

    procs = []   # only needed if args.parallel == True
    for day in days:
        for dev in args.devs:
            root_dir=os.path.join(args.folder, day, 'data', 'gnss', dev)
            flist = sorted(glob.glob(
                            '*.T02',
                            root_dir=root_dir,
                            ))
            print(day, dev, root_dir, flist)
            for f in flist:
                #print(f'{f}')
                f_in = os.path.join(root_dir, f)
                f_out = os.path.join(root_dir, f[0:-3] +'T04')

                cmd_list = [
                    args.t0x2t0x,
                    '--translate_rec27_to_rec35_sub19',
                    f_in,
                    f_out,
                ]
                print(' '.join(cmd_list))
                if not args.dryrun:
                    start = time.time()
                    log_fname = os.path.join(args.log_dir, f + "_t0x_decimate.log")
                    flog = open(log_fname, 'w')
                    if args.parallel:
                        # If we don't use nice, then the CPU gets so busy,
                        # that you can't even start a new SSH session.
                        cmd_list = ['nice', '-n',  '15'] + cmd_list
                        p = subprocess.Popen(
                            cmd_list, stderr=subprocess.STDOUT, stdout=flog
                        )
                        procs.append(
                                (p, flog, root_dir, start, log_fname)
                                )
                    else:
                        p = subprocess.run(
                            cmd_list, stderr=subprocess.STDOUT, stdout=flog
                        )
                        flog.close()
                        if p.returncode != 0:
                            logging.warning(f't0x2t0x return code {p.returncode}')

                        # Note: we need to scan the output from t0x2t0x because it seems
                        # to provide and exit code of 0, regardless of the error message
                        # being present or not. The typical error message is something like
                        # "T01 compression error 2: 21", which typically indicates that
                        # the t0x2t0x is older than the GNSS firmware used to collect the
                        # data.
                        with open(log_fname) as f:
                            if 'error' in f.read():
                                logging.warning(f"Found 'error' in {log_name}")

    if not args.dryrun and args.parallel:
        for n, (p, flog, root_dir, start, log_fname) in enumerate(procs):
                logging.debug(f'{n} {p.returncode=} {p.pid=} {root_dir=}')
        print('--------------------------------------------')
        while len(procs) > 0:
            for n, (p, flog, root_dir, start, log_fname) in enumerate(procs):
                if p.poll() is not None:
                    logging.debug(f'close {n} {p.returncode=} {p.pid=} {root_dir=}')
                    flog.close()
                    if p.returncode != 0:
                        logging.warning(f't0x2t0x for {root_dir} return code {p.returncode}')
                        print(f'------------- {log_fname} -----------------')
                        subprocess.run(['cat', log_fname])
                    # Note: we need to scan the output from t0x2t0x because it seems
                    # to provide and exit code of 0, regardless of the error message
                    # being present or not. The typical error message is something like
                    # "T01 compression error 2: 21", which typically indicates that
                    # the t0x2t0x is older than the GNSS firmware used to collect the
                    # data.
                    with open(log_fname) as f:
                        if 'error' in f.read():
                            logging.warning(f"Found 'error' in {log_name}")
                            print(f'------------- {log_fname} -----------------')
                            subprocess.run(['cat', log_fname])
                    end = time.time()
                    dt = end - start
                    if dt > 120:
                        print(f'Elapsed time for {root_dir}: {dt/60:0.3f} minutes')
                    else:
                        print(f'Elapsed time for {root_dir}: {dt:0.3f} seconds')
                    print('--------------------------------------------')
                    procs.pop(n)
            time.sleep(0.5)

if __name__ == '__main__':
    main()
