#!/usr/bin/env python
#  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
#
#  Use of this source code is governed by a BSD-style license
#  that can be found in the LICENSE file in the root of the source
#  tree. An additional intellectual property rights grant can be found
#  in the file PATENTS.  All contributing project authors may
#  be found in the AUTHORS file in the root of the source tree.

__author__ = 'kjellander@webrtc.org (Henrik Kjellander)'

import os
import gviz_api
import webrtc.data_helper

def main():
  """
  This Python script displays a web page with test created with the 
  video_quality_measurement program, which is a tool in WebRTC.
  
  The script requires on two external files and one Python library:
  - A HTML template file with layout and references to the json variables 
    defined in this script
  - A data file in Python format, containing the following:
    - test_configuration - a dictionary of test configuration names and values.
    - frame_data_types - a dictionary that maps the different metrics to their 
      data types.
    - frame_data - a list of dictionaries where each dictionary maps a metric to 
      it's value. 
  - The gviz_api.py of the Google Visualization Python API, available at
    http://code.google.com/p/google-visualization-python/
  
  The HTML file is shipped with the script, while the data file must be 
  generated by running video_quality_measurement with the --python flag
  specified.
  """
  print 'Content-type: text/html\n' # the newline is required!

  page_template_filename = '../templates/chart_page_template.html'
  # The data files must be located in the project tree for app engine being
  # able to access them.
  data_filenames = [ '../data/vp8_sw.py', '../data/vp8_hw.py' ]
  # Will contain info/error messages to be displayed on the resulting page.
  messages = []
  # Load the page HTML template.
  try:
    f = open(page_template_filename)
    page_template = f.read()
    f.close()
  except IOError as e:
    ShowErrorPage('Cannot open page template file: %s<br>Details: %s' % 
                  (page_template_filename, e))
    return
  
  # Read data from external Python script files. First check that they exist.
  for filename in data_filenames:
    if not os.path.exists(filename):
      messages.append('Cannot open data file: %s' % filename)
      data_filenames.remove(filename)
  
  # Read data from all existing input files.
  data_list = []
  test_configurations = []
  names = []
  
  for filename in data_filenames:
    read_vars = {} # empty dictionary to load the data into.
    execfile(filename, read_vars, read_vars)
    
    test_configuration = read_vars['test_configuration']
    table_description = read_vars['frame_data_types']
    table_data = read_vars['frame_data']
    
    # Verify the data in the file loaded properly.
    if not table_description or not table_data:
      messages.append('Invalid input file: %s. Missing description list or '
                      'data dictionary variables.' % filename)
      continue
    
    # Frame numbers appear as number type in the data, but Chart API requires
    # values of the X-axis to be of string type.
    # Change the frame_number column data type: 
    table_description['frame_number'] = ('string', 'Frame number')
    # Convert all the values to string types: 
    for row in table_data:
      row['frame_number'] = str(row['frame_number'])
    
    # Store the unique data from this file in the high level lists.
    test_configurations.append(test_configuration)
    data_list.append(table_data)
    # Name of the test run must be present.
    test_name = FindConfiguration(test_configuration, 'name')
    if not test_name:
      messages.append('Invalid input file: %s. Missing configuration key ' 
                      '"name"', filename)
      continue
    names.append(test_name)
    
  # Create data helper and build data tables for each graph.
  helper = webrtc.data_helper.DataHelper(data_list, table_description, 
                                         names, messages)
    
  # Loading it into gviz_api.DataTable objects and create JSON strings.
  description, data = helper.CreateConfigurationTable(test_configurations)
  configurations = gviz_api.DataTable(description, data)
  json_configurations = configurations.ToJSon()
  
  description, data = helper.CreateData('ssim')
  ssim = gviz_api.DataTable(description, data)
  json_ssim_data = ssim.ToJSon(helper.GetOrdering(description))
  
  description, data = helper.CreateData('psnr')
  psnr = gviz_api.DataTable(description, data)
  json_psnr_data = psnr.ToJSon(helper.GetOrdering(description))
  
  description, data = helper.CreateData('packets_dropped')
  packet_loss = gviz_api.DataTable(description, data)
  json_packet_loss_data = packet_loss.ToJSon(helper.GetOrdering(description))  
  
  description, data = helper.CreateData('bit_rate')
  # Add a column of data points for the desired bit rate to be plotted.
  # (uses test configuration from the last data set, assuming it is the same 
  # for all of them)
  desired_bit_rate = FindConfiguration(test_configuration, 'bit_rate_in_kbps')
  if not desired_bit_rate:
    ShowErrorPage('Cannot configuration field named "bit_rate_in_kbps"')
    return
  desired_bit_rate = int(desired_bit_rate)
  # Add new column data type description.
  description['desired_bit_rate'] = ('number', 'Desired bit rate (kbps)')
  for row in data:
    row['desired_bit_rate'] = desired_bit_rate
  bit_rate = gviz_api.DataTable(description, data)
  json_bit_rate_data = bit_rate.ToJSon(helper.GetOrdering(description))

  # Format the messages list with newlines.
  messages = '\n'.join(messages)
  
  # Put the variables as JSon strings into the template.
  print page_template % vars()

def FindConfiguration(configuration, name):
  """ Finds a configuration value using it's name. 
      Returns the first configuration with a matching name. Returns None if no
      matching configuration is found. """
  return_value = None
  for row in configuration:
    if row['name'] == name:
      return_value = row['value']
      break
  return return_value

def ShowErrorPage(error_message):
  print '<html><body>%s</body></html>' % error_message
  
if __name__ == '__main__':
  main()
