#!/usr/bin/env python

###############################################################################
# Copyright (c) 2010-2024 Trimble Inc.
# $Id: NoPiDI_Main.py,v 1.22 2024/06/18 21:35:49 acartmel Exp $
###############################################################################
#
# NoPiDI_Main.py
#
# Top-level functions to process the output from NoPi
# Generates plots and statistics for each satellite and each combo
# Creates a web page to view this information
#
###############################################################################

import sys
import gc
import matplotlib
matplotlib.use('agg')
import matplotlib.style
matplotlib.style.use('fast')

import os

from NoPiDI_Process import *
from NoPiDI_Create_Logo import *
from NoPiDI_Web_Page import *

from NoPiDI_Utils import *
add_utils_dir_to_path()

from NoPiUT_Load_Summary import *
from NoPiUT_Const import *


###############################################################################
# Debug option to disable plots for quicker testing
###############################################################################

#disable_plots()
enable_plots()


###############################################################################
# Parse command line
###############################################################################
import argparse

parser = argparse.ArgumentParser(description='Create a web page from NoPi data')
parser.add_argument('data_path', help='Path to NoPi output' )
parser.add_argument('-a', '--acq', help='Enable acquisition analysis', action='store_true' )
parser.add_argument('-p', '--parallel', help='Enable parallel plotting for speed', action='store_true' )
parser.add_argument('-n', '--no_per_sv', help='Disable per-SV plots for speed', action='store_true' )
parser.add_argument('-s', '--sv_slips', help='Show SV slips', action='store_true' )
# By default, the C/No single difference time series also plots a series of 120s averages. The averages
# are plotted with T=window/2. For data with jamming, this can obscure the gaps and result in C/No
# average spikes (e.g. low C/No for 90 seconds, followed by high C/No for 30, the average will show
# at 60s). Provide a way to disable plotting the red "x" average on the time series
parser.add_argument('-c', '--no_cno_avg', help='Disable plotting C/NO average', action='store_true' )
parser.add_argument('-e', '--sv_slips_elev', help='Elev. mask for cycle slips statistics, def 30deg', action='store' )
parser.add_argument('-y', '--override_y_axis_autoscaling', help='Over-ride the y-axis auto-scaling', action='store_true' )
args = parser.parse_args()

data_path = args.data_path
if args.acq:
  do_acq_flag = '-a'
else:
  do_acq_flag = 'x'
if args.parallel:
  set_parallel_plotting(True)
else:
  set_parallel_plotting(False)
if args.no_per_sv:
  set_per_sv_plotting(False)
else:
  set_per_sv_plotting(True)
if args.sv_slips:
  set_sv_plot_slips(True)
else:
  set_sv_plot_slips(False)
if args.no_cno_avg:
  set_cno_avg_plotting(False)
else:
  set_cno_avg_plotting(True)
if args.override_y_axis_autoscaling:
  set_y_axis_autoscaling(False)
else:
  set_y_axis_autoscaling(True)

# Ensure data path has suitable end slash and that the specified path exists
data_path = data_path_valid( data_path )

cslip_stats_elev_thr = 30
if args.sv_slips_elev:
  cslip_stats_elev_thr = int(args.sv_slips_elev)


###############################################################################
# Load summary file
###############################################################################

diffs_summ = cl_load_diffs_summ( data_path + 'diffs_summary.txt' )

# Acquisition Analysis will be done only if the user requests as an optional
# process. Can be done only if the measurement rate was greater than the
# acquisition analysis duration

if do_acq_flag == "-a" :
  if ( diffs_summ.do_acq_analysis ) :
    print(' Performing Acquisition Analysis ')
  else :
    print(' Cannot perform Acquisition Analysis - Data Rate unsupported ')
else :
  diffs_summ.do_acq_analysis = 0

# The file must be a valid extended data format at this point
# Checked in cl_load_diffs_summ()
ext_format = diffs_summ.file_format - 1

# Was the Az/El/CNo at the rover data read?
base_rovr_cno_read = False
if ( ext_format & cNoPiConst.DIFFS_FMT_BASE_ROVER ) :
  base_rovr_cno_read = True

# Was the D.D. Doppler data read?
doppler_read = False
if ( ext_format & cNoPiConst.DIFFS_FMT_DOPPLER ) :
  doppler_read = True


###############################################################################
# Create output directories
###############################################################################

if ( not( os.access( 'web', os.F_OK ) ) ) :
  print('Create web directory')
  os.mkdir( 'web' )

if ( not( os.access( 'plots', os.F_OK ) ) ):
  print('Create plots directory')
  os.mkdir( 'plots' )


###############################################################################
# Process the results for each combo
# Computes the statistics of the NoPi output and generates the plots
###############################################################################

meas_stats = []
acq_stats  = []
meas_ind   = 0
for combo in range( diffs_summ.num_combos ) :
  combo_fname = data_path + 'diffs_combo_' + str( int( combo ) ) + '.mtb'

  if ( diffs_summ.combo[ combo ].combo_vld ) :
    print('Processing file: ' + combo_fname)
    read_combo_file( diffs_summ, combo_fname )
  else :
    print('Skipping empty file: ' + combo_fname)

  # Process each of the measurements types
  for meas_type in range( cNoPiConst.NUM_MEAS_TYPE ) :
    gc.collect()

    # Include the plots of CNo vs elev?
    plot_raw_cno_elev = False
    if ( meas_type == cNoPiConst.MEAS_TYPE_SD_CNO and base_rovr_cno_read ) :
      plot_raw_cno_elev = True

    meas_stats.append( cl_meas() )
    acq_stats.append( cl_acq() )

    # Skip the Doppler if it is not in the data file
    # Ensure that the empty stats classes are appended first though
    if ( meas_type == cNoPiConst.MEAS_TYPE_DD_DOPP and not doppler_read ) :
      meas_ind += 1
      continue

    if ( diffs_summ.combo[ combo ].combo_vld ) :
      meas_stats[ meas_ind ] = process_meas( diffs_summ,
                                             combo,
                                             meas_type,
                                             plot_raw_cno_elev,
                                             cslip_stats_elev_thr
                                           )

      if ( diffs_summ.do_acq_analysis ) :
        acq_stats[ meas_ind ] = do_acq_analysis( diffs_summ, combo, meas_type )

    meas_ind += 1


###############################################################################
# Create the Trimble logo PNG file used by the web page
###############################################################################

create_logo_png()


###############################################################################
# Create combo statistics summary file
###############################################################################

create_stats_summary( diffs_summ, meas_stats, doppler_read )


###############################################################################
# Create web page to display results
###############################################################################

web_page = cl_web_page( diffs_summ, meas_stats, acq_stats )

web_page.input_data_file_section( diffs_summ )

web_page.create_all_combo_links( diffs_summ.do_acq_analysis,
                                 base_rovr_cno_read,
                                 doppler_read
                               )

for combo in range( diffs_summ.num_combos ) :
  if ( diffs_summ.combo[ combo ].combo_vld ) :
    web_page.create_single_combo_links( diffs_summ, combo, doppler_read )
  else :
    web_page.create_single_combo_empty( diffs_summ, combo )
