###############################################################################
# Copyright (c) 2011-2020 Trimble Inc.
# $Id: NoPiUT_Load_Summary.py,v 1.8 2020/07/06 16:46:59 acartmel Exp $
###############################################################################
#
# NoPiUT_Load_Summary.py
#
# Class used to contain the NoPi output combo information
# This is all read and decoded from the summary file output by NoPi
# It is therefore dependent on the summary file generation code in NoPi
#
###############################################################################

import sys
import os

from NoPiUT_Common_Meas import *
from NoPiUT_Const import *


###############################################################################
# Sub-class that contains the information that describes each signal combo
###############################################################################

class cl_combo_data :

  #############################################################################
  # Convert a single combo summary data line
  # Determines if the combo is valid for processing and displaying
  #############################################################################

  def __init__( self, fptr ) :
    st_loc = 0
    found  = 0

    # Read the combo line from the file
    tmp_line = fptr.readline()

    # Find and store each element from the line
    for x in range( len( tmp_line ) ) :
      if tmp_line[x] == ' ' :
        if ( found == 0 ) :
          self.ref_sat_type = tmp_line[ st_loc : x ]
        elif ( found == 1 ) :
          self.ref_sub_type = tmp_line[ st_loc : x ]
        elif ( found == 2 ) :
          self.tst_sat_type = tmp_line[ st_loc : x ]
        elif ( found == 3 ) :
          self.tst_sub_type = tmp_line[ st_loc : x ]
        elif ( found == 4 ) :
          self.epochs = int( tmp_line[ st_loc : x ] )

        found += 1
        st_loc = x + 1

    self.resolve_sdiff = int( tmp_line[ st_loc : x ] )

    # Determine if this combo is to be processed based on the
    # number of epochs recorded
    # Ignore files with less than 10 epochs of data
    if ( self.epochs > 10 ) :
      self.combo_vld = 1
    else :
      self.combo_vld = 0

###############################################################################
# Top-level class that contains all the summary information from NoPi
# Contains a sub-class for each signal combo
###############################################################################

class cl_load_diffs_summ :

  #############################################################################
  # Open the summary file and parse the contents
  #############################################################################

  def __init__( self, fname ) :

    # Parse the summary file only if it exists
    if ( os.access( fname, os.R_OK ) ) :

      self.fname = fname
      fptr = open( fname, 'rt' )

      # Parse the common contents

      # Parse Base File Information

      self.base_processor = []
      self.base_fw_date   = []
      self.base_fw_csum   = []
      self.base_fw_tow    = []

      self.base_fname     = self.read_line_rmv_ln_endins( fptr )
      self.base_model     = self.read_line_rmv_ln_endins( fptr )
      self.base_serial    = self.read_line_rmv_ln_endins( fptr )
      self.base_processor.append( self.read_line_rmv_ln_endins( fptr ) )
      self.base_fw_date.append( self.read_line_rmv_ln_endins( fptr ) )
      self.base_fw_csum.append( self.read_line_rmv_ln_endins( fptr ) )
      self.base_fw_tow.append( "N/A" )
      self.base_ip_add    = self.read_line_rmv_ln_endins( fptr )

      # Parse Rover File Information

      self.rovr_processor = []
      self.rovr_fw_date   = []
      self.rovr_fw_csum   = []
      self.rovr_fw_tow    = []

      self.rovr_fname     = self.read_line_rmv_ln_endins( fptr )
      self.rovr_model     = self.read_line_rmv_ln_endins( fptr )
      self.rovr_serial    = self.read_line_rmv_ln_endins( fptr )
      self.rovr_processor.append( self.read_line_rmv_ln_endins( fptr ) )
      self.rovr_fw_date.append( self.read_line_rmv_ln_endins( fptr ) )
      self.rovr_fw_csum.append( self.read_line_rmv_ln_endins( fptr ) )
      self.rovr_fw_tow.append( "N/A" )
      self.rovr_ip_add    = self.read_line_rmv_ln_endins( fptr )

      self.stime_ms = int( fptr.readline() )
      self.etime_ms = int( fptr.readline() )
      self.drate_ms = int( fptr.readline() )

      self.num_combos = int( fptr.readline() )

      # Determine if acquisition analysis must be performed. Acquisition
      # analysis can only be done for data collected at greater than the
      # duration of acquisition analysis
      if ( self.drate_ms < cNoPiConst.ACQ_ANALYSIS_DUR ) :
        self.do_acq_analysis = 1
      else :
        self.do_acq_analysis = 0

      # Parse the per combo contents

      self.combo = []
      for x in range( self.num_combos ) :
        self.combo.append( cl_combo_data( fptr ) )

      # NoPi output file format
      self.file_format = int( fptr.readline() )

      # New parameters not generated by older versions of NoPi

      # T01 library version (string)
      self.t01lib_ver = fptr.readline()
      if ( len(self.t01lib_ver) == 0 ) :
        self.t01lib_ver = "Not recorded"
      else :
        self.t01lib_ver = self.t01lib_ver[7:]

      # Antenna model library version (string)
      self.antlib_ver = fptr.readline()
      if ( len(self.antlib_ver) == 0 ) :
        self.antlib_ver = "Not recorded"
      else :
        self.antlib_ver = self.antlib_ver[7:]

      # Antenna model and name used at base
      tmp = fptr.readline()
      if ( len(tmp) == 0 ) :
        self.base_ant_num  = 0
        self.base_ant_name = "Not recorded"
      else :
        self.base_ant_num, self.base_ant_name \
          = self.decode_antenna_model( tmp )

      # Antenna model and name used at rover
      tmp = fptr.readline()
      if ( len(tmp) == 0 ) :
        self.rovr_ant_num  = 0
        self.rovr_ant_name = "Not recorded"
      else :
        self.rovr_ant_num, self.rovr_ant_name \
          = self.decode_antenna_model( tmp )

      # Base F/W versions recorded
      tmp = self.read_line_rmv_ln_endins( fptr )
      if ( len(tmp) != 0 ) :
        tstr, nfw = tmp.split( " ", 2 )
        for fw in range(int(nfw)) :
          self.base_processor.append( self.read_line_rmv_ln_endins( fptr ) )
          self.base_fw_date.append( self.read_line_rmv_ln_endins( fptr ) )
          self.base_fw_csum.append( self.read_line_rmv_ln_endins( fptr ) )
          self.base_fw_tow.append( self.read_line_rmv_ln_endins( fptr ) )

      # Rover F/W versions recorded
      tmp = self.read_line_rmv_ln_endins( fptr )
      if ( len(tmp) != 0 ) :
        tstr, nfw = tmp.split( " ", 2 )
        for fw in range(int(nfw)) :
          self.rovr_processor.append( self.read_line_rmv_ln_endins( fptr ) )
          self.rovr_fw_date.append( self.read_line_rmv_ln_endins( fptr ) )
          self.rovr_fw_csum.append( self.read_line_rmv_ln_endins( fptr ) )
          self.rovr_fw_tow.append( self.read_line_rmv_ln_endins( fptr ) )

      fptr.close()

    # If summary file cannot be found, flag an error and terminate
    # execution
    else :
      print('Missing summary file: %s' % fname)
      print('Terminating execution')
      sys.exit()

  #############################################################################
  # Utility function to remove the line endings from the base/rover file name
  # data
  #############################################################################

  def read_line_rmv_ln_endins( self, fptr ) :
    line = fptr.readline()
    if ( len( line ) > 2 and line[ len( line ) - 1 ] == '\n' ) :
      line = line[ 0 : len( line ) - 1 ]

    return( line )

  #############################################################################
  # Utility function to split the antenna type and name strings from the
  # summary file of format
  #   AntBase # "Name"
  #   AntRovr # "Name"
  #############################################################################

  def decode_antenna_model( self, text ) :
    tmp = text.split( " ", 2 )
    return( tmp[1], tmp[2] )
