###############################################################################
# Copyright (c) 2012-2020 Trimble Inc
# $Id: NoPiDI_javascript_func.py,v 1.7 2020/07/14 23:12:15 acartmel Exp $
###############################################################################
#
# NoPiDI_javascript_func.py
#
# Wrapper function to enclose the contents of the JavaScript functions as a
# string. This allows making a Python package easier with no dependencies on
# other files.
#
# Enclose as a raw string with either """ or ''' (triple quotes). This avoids
# having to escape end of lines with \n and include trailing backslash to
# indicate a long string
#
# To develop/debug the JavaScript, copy everything between the triple quotes
# to a separate file. Modify include_javascript_functions() so that the web
# browser sources this file:
#  f_top.write('<script text="language="JavaScript" src="tst.js"></script>\n')
# Now just need to refresh the web page after modifying the JavaScript. Copy
# back to this file when finished.
#
###############################################################################

def get_javascript_functions() :
  func_str = ''
  func_str = r"""
// Browsers (like Chrome) often don't allow scripting across iframes.
// Use postMessage() to bypass this restriction.  Example flow:
//  NoPiDI_Menu calls create_results_frame()
//  NoPiDI_Top gets message
//   -> forwards message to NoPiDI_Results
//
// For info. on grabbing the URL see:
// https://stackoverflow.com/questions/41228245/how-do-i-capture-a-url-parameter-from-parent-page-and-send-to-an-iframe-using-ja
function receiveMessage(event) {
  //console.log("Got event",event);
  if (event.data.url)
  {
    // Special event, the full URL of the parent send by the parent to
    // the two frames
    // Used to decode any parameters in the URL and construct the web
    // page links

    //console.log("F-URL")
    parse_url(event.data.url);
  }
  else
  {
    //console.log("F-other");
    document.getElementById('res_body').innerHTML
    = '<font face=\"arial\">'
    + event.data
    + cright_str
    + '</font>';
  }
}
window.addEventListener("message", receiveMessage, false) ;

// Call this function to write new HTML code to the
// results frameEdit
function create_results_frame( html_code ) {
  //console.log("Called create_results_frame()");
  top.postMessage(html_code,'*') ;
}

//  https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
function getParameterByName(name, url) {
  name = name.replace(/[\[\]]/g, "\\$&");
  var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
  results = regex.exec(url);
  if (!results) return '';
  if (!results[2]) return '';
  return decodeURIComponent(results[2].replace(/\+/g, " "));
}

// Decode any parameters from the URL
// i.e. NoPiDI_Top.html?show=all_plots&combo=-1&meas=0,1&plots=0
var base_url = '';
function parse_url( url )
{
  base_url = url.split('?')[0];
  var ptype = getParameterByName("show", url);
  var cbstr = getParameterByName("combo",url);
  var msstr = getParameterByName("meas", url);
  var svstr = getParameterByName("svid", url);
  var plstr = getParameterByName("plots",url);
  var cbarr = []; if (cbstr !== '') { cbarr = cbstr.split(','); }
  var msarr = []; if (msstr !== '') { msarr = msstr.split(','); }
  var svarr = []; if (svstr !== '') { svarr = svstr.split(','); }
  var plarr = []; if (plstr !== '') { plarr = plstr.split(','); }

  //console.log(ptype+' '+cbarr+' '+msarr+' '+svarr+' '+plarr);
  if ( ptype === "all_plots" ) {
    show_all_plots(cbarr, msarr, plarr[0]);
  }
  if ( ptype === "all_stats" ) {
    show_all_stats(cbarr, msarr, plarr);
  }
  if ( ptype === "ref_svs" ) {
    show_all_ref_svs( cbarr );
  }
  if ( ptype === "sv_stats" ) {
    show_sv_stats(cbarr, msarr, svarr);
  }
  if ( ptype === "acq_stats" ) {
    show_acq_sv_stats(cbarr, msarr, svarr);
  }
}

function add_page_link( ptype, cbarr, msarr, svarr, plarr ) {
  var link = base_url
           + "?show="  + ptype
           + "&combo=" + cbarr
           + "&meas="  + msarr
           + "&svid="  + svarr
           + "&plots=" + plarr;
  //var html_code = "Page Link: "+link+"<br>";
  var html_code = "<a href="+link+">&ltPage Link - right click to copy&gt</a><br>";

  return( html_code );
}

// Call this function to generate the web page to display
// the 'all satellite' plots
//   arr_combos - array of combos to display
//   arr_meas   - array of measurement types to display
//   cno_plots  - include CNo vs elevation plots?
function show_all_plots( arr_combos, arr_meas, cno_plots ) {
  var html_code = add_page_link('all_plots',arr_combos,arr_meas,[],[cno_plots]);

  if ( arr_combos[0] == -1 )
    arr_combos = vld_combos;

  for ( var i = 0; i < arr_combos.length; i++ ) {
    for ( var j = 0; j < arr_meas.length; j++ ) {
      html_code = html_code
                + '<a id="top"/>'
                + show_plots( [ 0 ], arr_meas[j], arr_combos[i], cno_plots );
    }
  }

  create_results_frame( html_code );
}


// Call this function to generate the HTML code to display
// a plot for a single satellite
//   sv_ind    - index into the sv array (in JavaScript data)
//   meas_type - measurement type to display
//   combo     - combo to display
//   cno_plots - include CNo vs elevation plots?
function show_plots( sv_ind, meas_type, combo, cno_plots ) {
  var html_code = '';
  var fname = '';
  var label = 'Unknown measurement type';
  var fname_base_cno = '../plots/' + 'base_cno_' + combo + '.png';
  var fname_rovr_cno = '../plots/' + 'rovr_cno_' + combo + '.png';
  var sv_str;
  var fname_tail;

  base_meas = meas_type % num_meas;
  if ( base_meas == dd_carr ) {
    fname = 'carr';
    label = 'Double Difference Carrier Phase';
  }
  else if ( base_meas == dd_code ) {
    fname = 'code';
    label = 'Double Difference Pseudorange';
  }
  else if ( base_meas == dd_dopp ) {
    fname = 'dopp';
    label = 'Double Difference Doppler';
  }
  else if ( base_meas == sd_cno ) {
    fname = 'cno';
    label = 'Single Difference CNo';
  }

  if ( sv_ind == 0 ) {
    sv_str = 'all';
  }
  else {
    sv_str = all_combo[combo].meas[0].sv[sv_ind].sv_id;
  }

  fname_tail = '_' + fname + '_' + sv_str  + '_' + combo + '.png';

  // Common handler for the raw difference plots and the distribution
  // plots
  if ( meas_type < acq_plts ) {
    var fname_time;
    var fname_elev;

    fname_dist = '../plots/dist' + fname_tail;
    fname_time = '../plots/time' + fname_tail;
    fname_elev = '../plots/elev' + fname_tail;

    if ( meas_type >= dist_plts ) {
      label = 'Distribution of ' + label;
    }

    html_code += '<h3>'
               + label
               + ' for Combo '
               + combo
               + ': '
               + all_combo[combo].combo_name
               + '</h3>\n';

    html_code += '<h4>'
               + ' Time Series Plot '
               + '</h4>\n'
               + '<img src="';
    if ( meas_type < dist_plts ) {
      html_code += fname_time;
    } else {
      html_code += fname_dist;
    }
    html_code += '" >\n';

    // The difference vs elevation plots are only available for the
    // raw difference data
    if ( meas_type < dist_plts ) {
      html_code += '<h4>\n'
                 + ' Residuals versus Elevation '
                 + '</h4>\n'
                 + '<img src="'
                 + fname_elev
                 + '" >\n';
    }

    // Display Base/Rover CNo versus elevation plots only when displaying
    // S.D. CNo plots for "All" SVs
    if ( base_meas == sd_cno && sv_ind == 0 && cno_plots ) {
      html_code += '<h4>\n'
                 + ' Base CNo versus Elevation '
                 + '</h4>\n'
                 + '<img src="'
                 + fname_base_cno
                 + '">'
                 + '<h4>\n'
                 + ' Rover CNo versus Elevation '
                 + '</h4>\n'
                 + '<img src="'
                 + fname_rovr_cno
                 + '">';
    }

    html_code += '<br > <br >'
               + '<a href="#top"> TOP </a>';
  }
  else if ( meas_type < cno_elev_plts ) {
    var fname_res = '../plots/dist_res' + fname_tail;
    var fname_mod200 = '../plots/dist_res_mod200' + fname_tail;
    var fname_acq_time = '../plots/time_acq' + fname_tail;

    label = 'Distribution of Acquisition Analysis ' + label;

    html_code += '<h3>'
                 + label
                 + ' for Combo '
                 + combo
                 + ': '
                 + all_combo[combo].combo_name
                 + '</h3>\n'
                 + ' '
                 + '<h4>'
                 + 'Acquisition Residual'
                 + '</h4>\n'
                 + '<img src="'
                 + fname_res
                 + '" >\n'
                 + '<h5>'
                 + ' '
                 + '</h5>\n'
                 + ' '
                 + '<img src="'
                 + fname_mod200
                 + '" >\n'
                 + ' '
                 + '<h4>'
                 + 'Time Series Acquisition Residual'
                 + '</h4>\n'
                 + '<img src="'
                 + fname_acq_time
                 + '" >'
                 + '<br > <br >'
                 + '<a href="#top"> TOP </a>';
  }
  else if ( meas_type == cno_elev_plts ) {
    label = 'Observed CNo versus Elevation at Base & Rover'

    // Display Base/Rover CNo versus elevation plots only when displaying
    // S.D. CNo plots for "All" SVs
    html_code += '<h3>'
               + label
               + ' for Combo '
               + combo
               + ': '
               + all_combo[combo].combo_name
               + '</h3>\n'
               + '<h4>'
               + ' Base CNo versus Elevation '
               + '</h4>\n'
               + '<img src="'
               + fname_base_cno
               + '">'
               + '<h4>\n'
               + ' Rover CNo versus Elevation '
               + '</h4>\n'
               + '<img src="'
               + fname_rovr_cno
               + '">'
               + '<br > <br >'
               + '<a href="#top"> TOP </a>';
  }

  return( html_code );
}


// Call this function to generate the web page to display
// the 'all satellite' statistics tables
//   arr_combos - array of combos to display
//   arr_meas   - array of measurement types to display stats
//   arr_plots  - array of indexes into the sv array to display plots
function show_all_stats( arr_combos, arr_meas, arr_plots ) {
  var html_code = add_page_link('all_stats',arr_combos,arr_meas,[],arr_plots);

  if ( arr_combos[0] == -1 )
    arr_combos = vld_combos;

  for ( var i = 0; i < arr_combos.length; i++ ) {
    html_code = html_code
              + show_stats( [ 0 ], arr_meas, arr_combos[i], arr_combos );
  }

  for ( var i = 0; i < arr_plots.length; i++ ) {
    for ( var j = 0; j < arr_meas.length; j++ ) {
      html_code = html_code
                + show_plots( [ 0 ], arr_meas[j], arr_plots[i], 0 );
    }
  }

  create_results_frame( html_code );
}


// Call this function to generate the web page to display
// the 'per satellites' statistics tables
//   combos     - combo to display
//   arr_meas   - array of measurement types to display stats
//   arr_sv_idx - array of indexes into the sv array to display plots
function show_sv_stats( combo, arr_meas, arr_sv_idx ) {
  var html_code = add_page_link('sv_stats',[combo],arr_meas,arr_sv_idx,[]);

  var arr_sv = new Array( all_combo[combo].num_svs );

  for ( var i = 0; i < all_combo[combo].num_svs; i++ ) {
    arr_sv[i] = all_combo[combo].meas[0].sv[i].sv_id;
  }

  html_code = html_code
            + show_stats( arr_sv, arr_meas, combo, [] );

  for ( var i = 0; i < arr_sv_idx.length; i++ ) {
    for ( var j = 0; j < arr_meas.length; j++ ) {
      html_code = html_code
                + show_plots( arr_sv_idx[i], arr_meas[j], combo, 0 );
    }
  }

  create_results_frame( html_code );
}


// Call this function to generate the web page to display
// the 'per satellites' acqusition statistics tables
//   combos     - combo to display
//   arr_meas   - array of measurement types to display stats
//   arr_sv_idx - array of indexes into the sv array to display plots
function show_acq_sv_stats( combo, arr_meas, arr_sv_idx ) {
  var html_code = add_page_link('acq_stats',[combo],arr_meas,arr_sv_idx,[]);

  var arr_sv = new Array( acq_combo[combo].num_svs );

  for ( var i = 0; i < acq_combo[combo].num_svs; i++ ) {
    arr_sv[i] = acq_combo[combo].acq[0].sv[i].sv_id;
  }

  html_code = show_acq_stats( arr_sv, arr_meas, combo, [] );

  for ( var i = 0; i < arr_sv_idx.length; i++ ) {
    for ( var j = 0; j < arr_meas.length; j++ ) {
      var meas_type = arr_meas[j] + acq_plts;
      html_code = html_code
                + show_plots( arr_sv_idx[i], meas_type, combo, 0 );
    }
  }

  create_results_frame( html_code );
}


// Call this function to generate the HTML code to display the differenced
// measurement statistics tables
//   arr_sv          - array of indexes into the sv array (in JavaScript data)
//   arr_meas        - array of measurement type to display
//   combo           - combo to display
//   arr_combos_link - array of combos being used on a statistics page
//                     only used to pass into other functions so that plots
//                     can be appended after statistics tables
function show_stats( arr_sv, arr_meas, combo, arr_combos_link ) {
  var html_code = '';

  // Create a title for the table
  html_code = '<h3>Measurement Statistics for Combo '
            + combo
            + ': '
            + all_combo[combo].combo_name
            + '</h3>';

  // Configure the table
  html_code = html_code + '<table border=\"1\" cellpadding=\"0\">';

  // Create measurement type column titles
  html_code = html_code + '<tr>'
  html_code = html_code + '<td></td>';
  for ( var i = 0; i < arr_meas.length; i++ ) {
    if ( arr_meas[i] == dd_carr )
      label = 'D.D. Carrier Phase';
    else if ( arr_meas[i] == dd_code )
      label = 'D.D. Pseudorange';
    else if ( arr_meas[i] == dd_dopp )
      label = 'D.D. Doppler';
    else if ( arr_meas[i] == sd_cno )
      label = 'S.D. CNo';
    else
      label = 'Unknown';

    html_code = html_code + '<th colspan=6 align=center>' + label + '</th>';
  }
  html_code = html_code + '</tr>';

  // Create per measurement column titles
  html_code = html_code + '<tr align=center>';
  html_code = html_code + '<th>SV Id</th>';
  for ( var i = 0; i < arr_meas.length; i++ ) {
    html_code = html_code
              + '<th>Epochs</th>'
              + '<th>Min '
              + all_combo[combo].meas[arr_meas[i]].units
              + '</th>'
              + '<th>Max '
              + all_combo[combo].meas[arr_meas[i]].units
              + '</th>'
              + '<th>Mean '
              + all_combo[combo].meas[arr_meas[i]].units
              + '</th>'
              + '<th>Std '
              + all_combo[combo].meas[arr_meas[i]].units
              + '</th>'
              + '<th>MAV '
              + all_combo[combo].meas[arr_meas[i]].units
              + '</th>';
  }
  html_code = html_code + '</tr>';

  // Populate the satellite ID information
  // Includes a link to display plots for this satellite
  for ( var i = 0; i < arr_sv.length; i++ ) {
    var tmp_sv;

    if ( arr_combos_link.length ) {
      tmp_sv = '<a href="javascript:show_all_stats( ['
             + arr_combos_link
             + '], ['
             + arr_meas
             + '], ['
             + combo
             + '] )">';
    }
    else {
      tmp_sv = '<a href="javascript:show_sv_stats( ['
             + combo
             + '], ['
             + arr_meas
             + '], ['
             + i
             + '] )">';
    }

    if ( arr_sv[i] == 0 )
      tmp_sv = tmp_sv + 'All';
    else
      tmp_sv = tmp_sv + arr_sv[i];

    tmp_sv = tmp_sv + '</a>';

    html_code = html_code + '<tr align=center><th>' + tmp_sv + '</th>';

    // Populate the measurement statistics
    for ( var j = 0; j < arr_meas.length; j++ ) {
      html_code = html_code
                + '<td>'
                + all_combo[combo].meas[arr_meas[j]].sv[i].vld_epochs
                + '</td>'
                + '<td>'
                + all_combo[combo].meas[arr_meas[j]].sv[i].vld_min
                + '</td>'
                + '<td>'
                + all_combo[combo].meas[arr_meas[j]].sv[i].vld_max
                + '</td>'
                + '<td>'
                + all_combo[combo].meas[arr_meas[j]].sv[i].vld_mean
                + '</td>'
                + '<td>'
                + all_combo[combo].meas[arr_meas[j]].sv[i].vld_std
                + '</td>'
                + '<td>'
                + all_combo[combo].meas[arr_meas[j]].sv[i].vld_mav
                + '</td>';
    }

    html_code = html_code + '</tr>';
  }

  html_code = html_code + '</table>';

  return( html_code );
}


// Call this function to generate the HTML code to display
// statistics tables
//   arr_sv          - array of indexes into the sv array (in JavaScript data)
//   arr_meas        - array of measurement type to display
//   combo           - combo to display
//   arr_combos_link - array of combos being used on a statistics page
//                     only used to pass into other functions so that plots
//                     can be appended after statistics tables
function show_acq_stats( arr_sv, arr_meas, combo, arr_combos_link ) {
  var html_code = '';

  // Create a title for the table
  html_code = '<h3>Acquisition Performance Analysis for Combo '
            + combo
            + ': '
            + acq_combo[combo].combo_name
            + '</h3>';

  // Configure the table
  html_code = html_code + '<table border=\"1\" cellpadding=\"0\">';

  // Create measurement type column titles
  html_code = html_code + '<tr>'
  html_code = html_code + '<td></td>';
  for ( var i = 0; i < arr_meas.length; i++ ) {
    if ( arr_meas[i] == dd_carr )
      label = 'D.D. Carrier Phase';
    else if ( arr_meas[i] == dd_code )
      label = 'D.D. Pseudorange';
    else if ( arr_meas[i] == dd_dopp )
      label = 'D.D. Doppler';
    else if ( arr_meas[i] == sd_cno )
      label = 'S.D. CNo';
    else
      label = 'Unknown';

    html_code = html_code + '<th colspan=8 align=center>' + label + '</th>';
  }
  html_code = html_code + '</tr>';

  // Create per measurement column titles
  html_code = html_code + '<tr align=center>';
  html_code = html_code + '<th>SV Id</th>';
  for ( var i = 0; i < arr_meas.length; i++ ) {
    html_code = html_code
              + '<th>Epochs</th>'
              + '<th># of Acquisition</th>'
              + '<th>Mean %200ms '
              + acq_combo[combo].acq[arr_meas[i]].units
              + '</th>'
              + '<th>Std %200ms '
              + acq_combo[combo].acq[arr_meas[i]].units
              + '</th>'
              + '<th> Abv threshold'
              + acq_combo[combo].acq[arr_meas[i]].units
              + '</th>'
              + '<th>Mean !%200ms '
              + acq_combo[combo].acq[arr_meas[i]].units
              + '</th>'
              + '<th>Std !%200ms '
              + acq_combo[combo].acq[arr_meas[i]].units
              + '</th>'
              + '<th> Abv threshold'
              + acq_combo[combo].acq[arr_meas[i]].units
              + '</th>';
  }
  html_code = html_code + '</tr>';

  // Populate the satellite ID information
  // Includes a link to display plots for this satellite
  for ( var i = 0; i < arr_sv.length; i++ ) {
    var tmp_sv;

    if ( arr_combos_link.length ) {
      tmp_sv = '<a href="javascript:show_all_stats( ['
             + arr_combos_link
             + '], ['
             + arr_meas
             + '], ['
             + combo
             + '] )">';
    }
    else {
      tmp_sv = '<a href="javascript:show_acq_sv_stats( ['
             + combo
             + '], ['
             + arr_meas
             + '], ['
             + i
             + '] )">';
    }

    if ( arr_sv[i] == 0 )
      tmp_sv = tmp_sv + 'All';
    else
      tmp_sv = tmp_sv + arr_sv[i];

    tmp_sv = tmp_sv + '</a>';

    html_code = html_code + '<tr align=center><th>' + tmp_sv + '</th>';

    // Populate the measurement statistics
    for ( var j = 0; j < arr_meas.length; j++ ) {
      html_code = html_code
                + '<td>'
                + acq_combo[combo].acq[arr_meas[j]].sv[i].vld_epochs
                + '</td>'
                + '<td>'
                + acq_combo[combo].acq[arr_meas[j]].sv[i].num_acq
                + '</td>'
                + '<td>'
                + acq_combo[combo].acq[arr_meas[j]].sv[i].mean_res
                + '</td>'
                + '<td>'
                + acq_combo[combo].acq[arr_meas[j]].sv[i].std_res
                + '</td>'
                + '<td>'
                + acq_combo[combo].acq[arr_meas[j]].sv[i].res_abv_thresh
                + '%'
                + '</td>'
                + '<td>'
                + acq_combo[combo].acq[arr_meas[j]].sv[i].mean_mod200
                + '</td>'
                + '<td>'
                + acq_combo[combo].acq[arr_meas[j]].sv[i].std_mod200
                + '</td>'
                + '<td>'
                + acq_combo[combo].acq[arr_meas[j]].sv[i].mod200_abv_thresh
                + '%'
                + '</td>'
    }

    html_code = html_code + '</tr>';

  }

  html_code = html_code + '</table>';

  return( html_code );
}


// Call this function to generate the web page to display
// the reference satellite plots
//   arr_combos - array of combos to display
function show_all_ref_svs( arr_combos ) {
  var html_code = add_page_link('ref_svs',arr_combos,[],[],[]);

  if ( arr_combos[0] == -1 )
    arr_combos = vld_combos;

  for ( var i = 0; i < arr_combos.length; i++ ) {
    html_code = html_code
              + '<a id="top"/>'
              + show_ref_svs( arr_combos[i] );
  }

  create_results_frame( html_code );
}


// Call this function to generate the HTML code to display
// the reference satellite for the given combo
//   combo - combo to display
function show_ref_svs( combo ) {
  var fname = '../plots/ref_svs_all_' + combo + '.png';
  var html_code = '<h3>'
                + 'Double Difference Reference Satellite for Combo '
                + combo
                + ': '
                + all_combo[combo].combo_name
                + '</h3>\n'
                + '<img src="'
                + fname
                + '">';

  return( html_code );
}

"""

  return( func_str )
