#!/usr/bin/python3

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


def read_ini(fname):
    f = open(fname, 'r')
    lines = f.readlines()
    cmd = []
    for line in lines:
        if line.strip().startswith('#'):
            continue
        for field in line.strip().split():
            if field.startswith('#'):
                break
            cmd.append(field)
    return cmd


def get_t04_list(folder):
    logging.info(f'{folder=}')
    if not os.path.isdir(folder):
        logging.warning(f'Skipping {folder}, it is not a directory.')
        return []
    t04_list = []
    with os.scandir(folder) as it:
        for entry in it:
            f = entry.name
            #print(f'{f=}')
            if entry.is_dir() or f.startswith('_') or f.startswith('.'):
                continue
            #print(f'{f=}')
            if f.endswith('T04'):
                t04_list.append(os.path.join(folder, f))
    t04_list.sort()
    return t04_list


def main():
    parser = argparse.ArgumentParser(
        description='Run TitanPlayer on FOLDER/',
        epilog="Skip folders starting with '.' or '_'",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
        )
    parser.add_argument(
        '-F', '--folder',
        default='.',
        help='Root dir containing T04 Files.',
        )
    parser.add_argument(
        '-D', '--devs',
        type=str,
        nargs='+',
        default=['BX992', 'EB1-5093', 'EB1-5095', 'EB-5081', 'P4-05'],
        help="List of dev directories, will be used as FOLDER/day/data/gnss/DEV"
             "If None, then scan FOLDER/day/data/gnss/ for dev directories that "
             "do not start with '.' or '_'. "
             "Example: -D BXLVL JudoRoof P4-05 MS956",
        )

    titanp = parser.add_argument_group('TitanPlayer options')
    titanp.add_argument(
        "--ini",
        default='vsbl.ini',
        help="Arguments to pass to TitanPlayer. See 'vsbl-static.ini' and "
             "'no-vsbl-static.ini' for examples. '-outputFolder' and "
             "'-inputRovFiles' will be added to the commands in the ini file "
             "by this script.",
        )
    titanp.add_argument(
        '--tp',
        default='auto',
        help="Full TitanPlayer path. for 'auto', let the OS determine it.",
        )
    titanp.add_argument(
        '--hud_dir',
        default='titan',
        help="Import HUD file(s) from FOLDER/hud_dir/DUT_DIR/",
        )
    titanp.add_argument(
        '--rtk',
        default='240918/Strip_all.T04',
        help="Name of GNSS Base observation T04 file."
             "Pass FOLDER/*/data/gnss/rtk_dir/*.T0[24] to TitanPlayer",
        )

    outp = parser.add_argument_group('Output Options')
    outp.add_argument(
        '--data_out_dir',
        default='outputs',
        help="Where to store .csv, .feather, .json output files",
        )
    outp.add_argument(
        '--log_dir',
        default='logs',
        help="where to put the log (.txt) from running TitanPlayer. "
             "It will be used as FOLDER/LOG_DIR/",
        )

    debugp = parser.add_argument_group('Debug Options')
    debugp.add_argument(
        '-n', "--dryrun",
        action='store_true',
        help="Skip running t0x2t0x"
        )
    debugp.add_argument(
        '-1', "--do_one",
        action='store_true',
        help="Skip running t0x2t0x"
        )
    debugp.add_argument(
        "--verbose", "-v",
        action='count',
        default=0,
        help="use multiple -v for more detailed messages."
    )

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

    logging.info(f'{os.name=}')
    if os.name == 'Linux' or os.name == 'posix':
        if args.tp == 'auto':
            tp_exe = 'TitanPlayer'
    elif os.name == 'nt':  # Windows
        if args.tp == 'auto':
            tp_exe = os.path.join(
                  'D:', os.sep, 'TitanPlayer', 'bin', 'TitanPlayer.exe'),
    else:
        print('ERROR only Linux or Windows expected')
        sys.exit()

    if args.tp != 'auto':
        tp_exe = args.tp

    args.folder = os.path.abspath(args.folder)
    logging.info(f'{args.folder=}')

    procs = []   # only needed if args.parallel == True
    for dev in args.devs:
        d = os.path.join(args.folder, f'{dev}.T04')
        #if 'figures' in d or 'logs' in d:
        #        continue
        if not os.path.isfile(d):
            print(f'Skipping missing T04 file: {d}')
            continue
        print(f'----------------- {dev} ---------------------------')

        #logging.debug(f'{args.in_dir=}')
        #logging.debug(f'{dev=}')
        out_dir = os.path.join(
              args.folder, args.data_out_dir, args.hud_dir, dev)
        log_fname = os.path.join(out_dir, f'TitanPlayer_{dev}.log')
        print(f'   {log_fname=}')

        cmd = ['nice', '-n',  '15',  # If we don't use nice, then the CPU gets so busy, that you can't even start a new SSH session.
               tp_exe,
               '-outputFolder', out_dir,
               ]
        cmd += read_ini(args.ini)
        cmd += ['-inputRovFiles'] + [d]
        if args.rtk:
            cmd += ['-ignoreCorrInRovFile', '-inputRefFiles'] + [os.path.abspath(args.rtk)]

        print(f'   {out_dir=}')
        #print(f'   {log_fname}')
        #print('\n'.join(cmd))
        if not args.dryrun:
            os.makedirs(out_dir, exist_ok=True)
            with open(os.path.join(out_dir, 'TitanPlayer.cmd.txt'), 'w') as fcmd:
                for line in cmd:
                    fcmd.write(f"{line}\n")

        if not args.dryrun:
            start = time.time()
            flog = open(log_fname, 'w')
            p = None
            p = subprocess.Popen(cmd,
                                 cwd=out_dir,
                                 stderr=subprocess.STDOUT, stdout=flog,
                                 )
            procs.append((p, flog, out_dir, start, d, dev))
            logging.info('TitanPlayer started')
        if args.do_one:
            break

    if not args.dryrun:
        for n, (p, flog, out_dir, start, d, dev) in enumerate(procs):
                logging.debug(f'{n} {p.returncode=} {p.pid=} {d=} {dev=}')
        print('--------------------------------------------')
        while len(procs) > 0:
            for n, (p, flog, out_dir, start, d, dev) in enumerate(procs):
                #(p, flog, out_dir, start, d, dev) = item
                if p.poll() is not None:
                    logging.debug(f'close {n} {p.returncode=} {p.pid=} {d=} {dev=}')
                    flog.close()
                    if p.returncode != 0:
                        logging.warning(f'TitanPlayer for {d} return code {p.returncode}')
                        log_fname = os.path.join(out_dir, f'TitanPlayer_{dev}.log')
                        logging.warning(f'------------- {log_fname} -----------------')
                        subprocess.run(['cat', log_fname])
                    end = time.time()
                    dt = end - start
                    if dt > 120:
                        print(f'Elapsed time for {d}, {dev}: {dt/60:0.3f} minutes')
                    else:
                        print(f'Elapsed time for {d}, {dev}: {dt:0.3f} seconds')
                    print('--------------------------------------------')

                    # We shouldn't need this anymore, now that we do cwd=out_dir
                    #for f in [
                    #         os.path.join(out_dir, 'NavSolnEnums.txt'),
                    #         os.path.join(out_dir, 'SatUsageDiagnosticEnums.txt'),
                    #         os.path.join(out_dir, 'IonoDisturbanceInfo.txt'),
                    #]:
                    #    if os.path.isfile(f):
                    #        logging.info(f'Moving {os.path.split(f)[1]} -> {out_dir}')
                    #        os.rename(f, os.path.join(out_dir, f))
                    procs.pop(n)
            time.sleep(0.5)


if __name__ == '__main__':
    main()
