###############################################################################
# Copyright (c) 2012 Trimble Navigation Ltd
# $Id: NoPiSD_Process.py,v 1.1 2012/02/04 01:08:47 shankar Exp $
###############################################################################
#
# NoPiSD_Process.py
#
# This file contains functions used to read stats_combo files and
# generate long term trend plots for each metric
###############################################################################

from pylab import *

from NoPiSD_Plot import *
from NoPiSD_Utils import *
add_utils_dir_to_path()

from NoPiUT_Common_Meas import get_metrics_list, get_metrics_column
from NoPiUT_Common_Display import *

global metric_list, num_metric
metric_list = get_metrics_list()
num_metrics = len( metric_list )

###############################################################################
# Wrapper function to generate long term trends using method 1. Generates one
# plot per metric/meas_type/combo/receiver pair baseline. Both auto scaled and
# fixed scaled plots are generated.
###############################################################################

def gen_trends_method_1( concat_summ, 
                         data_path ) :
  method = 1

  # loop over all receiver pair baselines read from concat summary file
  for baseline_idx in range( concat_summ.num_baselines ) :

    [orig_baseline_name, new_baseline_name] = update_baseline_name( concat_summ, 
                                                                    baseline_idx )

    # check if trend plots output directory exists
    trend_dir_name = create_trends_dir( method, baseline = new_baseline_name ) 

    # loop over combo/mtype/metric to generate trends 
    for combo_idx in range( concat_summ.num_combos ) :
      combo_name = concat_summ.combo[ combo_idx ].combo_name
      combo_sd_amb = concat_summ.combo[ combo_idx ].resolve_sdiff
      # Read concatenated statistics file
      [ stats_in, load_ok ] = load_stats_data( concat_summ, data_path, 
                                               baseline_idx, combo_idx )
      # Can proceed further only if the file was found and parsed
      if ( load_ok ) :
        # loop over the three measurement types
        for mtype in range( 3 ) :
          index_mtype = find( stats_in[ :, 2 ] == mtype )
          if ( mtype == 0 and combo_sd_amb == 1 ) :
            stats_in[index_mtype, :] = scale_mm_to_mcycles( stats_in[index_mtype,:],
                                                            combo_name )
          # loop over each metric
          for idx, metric in enumerate( metric_list ) :
            # generate trend plots for each metric
            metric_col = get_data_column( metric )
            gen_trend_plots( stats_in[ index_mtype, : ],
                             concat_summ, 
                             metric, 
                             fig_num = idx,
                             label = get_legend_name( orig_baseline_name )
                           )
            save_and_close_fig( concat_summ, 
                                trend_dir_name, 
                                method,
                                fig_num = idx,
                                metric = metric, 
                                mtype = mtype, 
                                baseline = new_baseline_name,
                                combo_idx = combo_idx 
                              ) 

###############################################################################
# Wrapper function to generate long term trends using method 2. Generates one
# plot per metric/meas_type/combo/physical baseline. Physical baseline can be
# one of three:
# 1. physical zero baseline
# 2. physical short baseline
# 3. antenna switch setup receiver pairs
# Both auto scaled and fixed scaled plots are generated.
###############################################################################

def gen_trends_method_2( concat_summ, 
                         data_path ) :

  method = 2
  [zero_base_idx, short_base_idx, relock_idx] = get_phy_baseline_idx( concat_summ )

  # generate trends for each combo  
  for combo_idx in range( concat_summ.num_combos ) :
    print 'Generating trends for combo: %s' % concat_summ.combo[combo_idx].combo_name
    # Loop over physical baselines and include all receiver pair belonging to a
    # particular physical baseline in the same plot
    # physical zero baseline 
    for baseline_idx in zero_base_idx :
      gen_individual_trends( concat_summ, data_path, 
                             method,
                             baseline_idx = baseline_idx, 
                             combo_idx = combo_idx )
    trend_dir_name = create_trends_dir( method, baseline = 'Zero_Baseline' )
    save_and_close_individual_plots( concat_summ, trend_dir_name, 
                                     method,
                                     baseline = 'Zero_Baseline',
                                     combo_idx = combo_idx )
    # physical short baseline
    for baseline_idx in short_base_idx :
      gen_individual_trends( concat_summ, data_path, 
                             method,
                             baseline_idx = baseline_idx, 
                             combo_idx = combo_idx )
    trend_dir_name = create_trends_dir( method, baseline = 'Short_Baseline' )
    save_and_close_individual_plots( concat_summ, trend_dir_name, 
                                     method,
                                     baseline = 'Short_Baseline',
                                     combo_idx = combo_idx )
    # antenna switch receiver pairs
    for baseline_idx in relock_idx :
      gen_individual_trends( concat_summ, data_path,
                             method, 
                             baseline_idx = baseline_idx, 
                             combo_idx = combo_idx )
    trend_dir_name = create_trends_dir( method, baseline = 'Antenna_Switch' )
    save_and_close_individual_plots( concat_summ, trend_dir_name, 
                                     method,
                                     baseline = 'Antenna_Switch',
                                     combo_idx = combo_idx )


###############################################################################
# Wrapper function to generate long term trends using method 3. Generates one
# plot per metric/meas_type/receiver pair baseline. GLONASS Carrier phase
# results are scaled from mm to mcycles Both auto scaled and fixed scaled plots
# are generated.
###############################################################################

def gen_trends_method_3( concat_summ, data_path ) :

  method = 3

  for baseline_idx in range( concat_summ.num_baselines ) :
    [orig_baseline_name, new_baseline_name] = update_baseline_name( concat_summ,
                                                                    baseline_idx )
    for combo_idx in range( concat_summ.num_combos ) :
      gen_individual_trends( concat_summ, data_path, method,
                             baseline_idx, combo_idx )
    # Check if output directory exists
    trend_dir_name = create_trends_dir( method, baseline = new_baseline_name ) 
    save_and_close_individual_plots( concat_summ, trend_dir_name, method, 
                                     baseline = new_baseline_name
                                   )


###############################################################################
# Wrapper function to generate long term trends using method 4. Generates one
# plot per metric/meas_type/physical baseline. GLONASS Carrier phase data are
# scaled from mm to mcycles. Both auto scaled and fixed scaled plots are
# generated.
###############################################################################

def gen_trends_method_4( concat_summ, 
                         data_path ) :

  method = 4
  [zero_base_idx, short_base_idx, relock_idx] = get_phy_baseline_idx( concat_summ )

  # Loop over each all receiver pairs belonging to a particular physical
  # baseline setup. Display trends for all combos on a single plot
  # Physical Zero Baseline
  for baseline_idx in zero_base_idx :
    update_baseline_name( concat_summ, baseline_idx )
    for combo_idx in range( concat_summ.num_combos ) :
      gen_individual_trends( concat_summ, data_path, 
                             method,
                             baseline_idx = baseline_idx, 
                             combo_idx = combo_idx )
  trend_dir_name = create_trends_dir( method, baseline = 'Zero_Baseline' )
  save_and_close_individual_plots( concat_summ, trend_dir_name, 
                                   method,
                                   baseline = 'Zero_Baseline' )

  # Physical Short Baseline
  for baseline_idx in short_base_idx :
    update_baseline_name( concat_summ, baseline_idx )
    for combo_idx in range( concat_summ.num_combos ) :
      gen_individual_trends( concat_summ, data_path, 
                             method,
                             baseline_idx = baseline_idx, 
                             combo_idx = combo_idx )
  trend_dir_name = create_trends_dir( method, baseline = 'Short_Baseline' )
  save_and_close_individual_plots( concat_summ, trend_dir_name, 
                                   method,
                                   baseline = 'Short_Baseline' )
  # Antenna Switch Receiver Pairs
  for baseline_idx in relock_idx :
    update_baseline_name( concat_summ, baseline_idx )
    for combo_idx in range( concat_summ.num_combos ) :
      gen_individual_trends( concat_summ, data_path, 
                             method,
                             baseline_idx = baseline_idx, 
                             combo_idx = combo_idx )
  trend_dir_name = create_trends_dir( method, baseline = 'Antenna_Switch' )
  save_and_close_individual_plots( concat_summ, trend_dir_name, 
                                   method,
                                   baseline = 'Antenna_Switch' )


###############################################################################
# Wrapper function to generate long term trends using method 5. Generates one
# plot per metric/meas_type. GLONASS Carrier phase data are scaled from mm to
# mcycles. All combos and receiver pairs are plotting on a single plot. 
# Both auto scaled and fixed scaled plots are generated.
###############################################################################

def gen_trends_method_5( concat_summ, data_path ) :

  method = 5

  trend_dir_name = create_trends_dir( method, baseline = '' )

  # Loop over each metric and meas_type
  for metric_idx, metric in enumerate( metric_list ) :
    print 'Processing Metric: %s' % metric
    for baseline_idx in range( concat_summ.num_baselines ) :
      for combo_idx in range( concat_summ.num_combo ) :
        combo_name = concat_summ.combo[ combo_idx ].combo_name
        combo_sd_amb = concat_summ.combo[ combo_idx ].resolve_sdiff
        [ label, color ] = get_plot_label_color( concat_summ, method, 
                                                 baseline_idx, combo_idx )
        [stats_in, load_ok ] = load_stats_data( concat_summ, data_path, 
                                                baseline_idx, combo_idx )
        if ( load_ok ) : 
          for mtype in range( 3 ) :
            index_mtype = find( stats_in[ :, 2 ] == mtype ) 
            if ( mtype == 0 and combo_sd_amb == 1 ) :
              stats_in[index_mtype,:] = scale_mm_to_mcycles( stats_in[index_mtype,:],
                                                             combo_name )
            gen_trend_plots( stats_in[ index_mtype, : ],
                             concat_summ,
                             metric,
                             fig_num = mtype,
                             label = label,
                             color = color
                           )
    # Save and close trends for each metric prior to incrementing to the next
    # metric
    for mtype in range( 3 ) :
      save_and_close_fig( concat_summ, trend_dir_name, method, 
                          fig_num = mtype, 
                          metric = metric, 
                          mtype = mtype 
                        )


###############################################################################
# Common wrapper function to loop over all measurement types and metrics and
# generate trends based on the specified method
###############################################################################

def gen_individual_trends( concat_summ, 
                           data_path, 
                           method,
                           baseline_idx,
                           combo_idx ) :
  # Work out plot color and legend label based on method specified
  [ label, color ] = get_plot_label_color( concat_summ, method, 
                                           baseline_idx, combo_idx )
  # Read concatenated stats data if the file exists
  [stats_in, load_ok ] = load_stats_data( concat_summ, data_path, 
                                          baseline_idx, combo_idx )
  # If data was read, generate trends using the method specified
  if ( load_ok ) : 
    # Loop over all three measurement types
    for mtype in range( 3 ) :
      idx_mtype = find( stats_in[ :, 2 ] == mtype ) 
      combo_name = concat_summ.combo[ combo_idx ].combo_name
      combo_sd_amb = concat_summ.combo[ combo_idx ].resolve_sdiff
      # Scale S.D. Ambiguity resolved carrier phase results from mm to
      # mcycles. This ensures different combos have the same scale when
      # displaying all combos in a single plot
      if ( mtype == 0 and combo_sd_amb == 1 ) :
        stats_in[ idx_mtype,: ] = scale_mm_to_mcycles( stats_in[idx_mtype,:],
                                                         combo_name )
      # Loop over each metric
      for metric_idx, metric in enumerate( metric_list ) :
        gen_trend_plots( stats_in[ idx_mtype, : ],
                         concat_summ,
                         metric,
                         fig_num = ( metric_idx + mtype*num_metrics ),
                         label = label,
                         color = color
                       )


###############################################################################
# Wrapper function to invoke save_and_close_fig() defined in NoPiSD_Plot.py
# Optional parameters are passed in as a dictionary
###############################################################################

def save_and_close_individual_plots( concat_summ, 
                                     trend_dir_name, 
                                     method,
                                     **kwargs
                                   ) :
  for mtype in range( 3 ) :
    for metric_idx, metric in enumerate( metric_list ) :
      save_and_close_fig( concat_summ,
                          trend_dir_name, 
                          method,
                          fig_num = ( metric_idx + mtype*num_metrics ),
                          metric = metric, 
                          mtype = mtype,
                          **kwargs )


###############################################################################
# Wrapper function to scale S.D. ambiguity resolution carrier phase results 
# from mm to mcycles. Scaling is only required for
# Mean/Median/Std. Dev/MADN. The remaining metrics are scale invariant
###############################################################################

def scale_mm_to_mcycles( stats_in, combo_name ) :

  scalable_metrics = ['MEAN', 'MEDIAN', 'STD', 'MADN']

  for metric_idx, metric in enumerate( metric_list ) :
    if ( metric.upper( ) in scalable_metrics ) :
      metric_col = get_concat_file_metric_column( metric )
      stats_in[:,metric_col ] = convert_mm_to_mcycles( stats_in[:,metric_col],
                                                       combo_name )

  return( stats_in )


###############################################################################
# Work out plot legend name and line color
###############################################################################

def get_plot_label_color( concat_summ, 
                          method, 
                          baseline_idx, 
                          combo_idx ) :

  if ( method == 2 ) :
    baseline_name = concat_summ.baseline[ baseline_idx ].baseline_dir
    label = get_legend_name( baseline_name )
    color = get_colour( baseline_idx )
  else :
    combo_name = concat_summ.combo[ combo_idx ].combo_name
    combo_short_name = get_combo_short_name( combo_name )
    label = combo_short_name
    color = get_stats_colour( baseline_idx*concat_summ.num_combos + combo_idx )

  return( label, color )


###############################################################################
# Inform user about current processing state. Apollo Zero baseline is named as
# '' in concatenation summary file. Change name from '' to 'Apollo_Zero' for
# user readability 
# Common to methods 1,3 and 4
###############################################################################

def update_baseline_name( concat_summ, baseline_idx ) :
  orig_baseline_name = concat_summ.baseline[baseline_idx].baseline_dir

  # Update baseline name for the Apollo Zero baseline. 
  new_baseline_name = orig_baseline_name
  if ( orig_baseline_name == '' ) :
    new_baseline_name = 'Apollo_Zero'
  print 'Processing Baseline: ' + new_baseline_name
  print '------------------------------------------------------------'

  return ( orig_baseline_name, new_baseline_name )
