#!/usr/bin/env python
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import itertools
import json
import os.path
import sys
import optparse
_script_path = os.path.realpath(__file__)

sys.path.insert(0, os.path.normpath(_script_path + "/../../json_comment_eater"))
try:
  import json_comment_eater
finally:
  sys.path.pop(0)

sys.path.insert(0, os.path.normpath(_script_path + "/../../json_to_struct"))
try:
  import json_to_struct
finally:
  sys.path.pop(0)

def _Load(filename):
  """Loads a JSON file into a Python object and return this object.
  """
  with open(filename, 'r') as handle:
    result = json.loads(json_comment_eater.Nom(handle.read()))
  return result

def _LoadFieldTrialConfig(filename, platform):
  """Loads a field trial config JSON and converts it into a format that can be
  used by json_to_struct.
  """
  return _FieldTrialConfigToDescription(_Load(filename), platform)

def _CreateExperiment(experiment_data):
  experiment = {'name': experiment_data['name']}
  forcing_flags_data = experiment_data.get('forcing_flag')
  if forcing_flags_data:
    experiment['forcing_flag'] = forcing_flags_data
  params_data = experiment_data.get('params')
  if (params_data):
    experiment['params'] = [{'key': param, 'value': params_data[param]}
                          for param in sorted(params_data.keys())];
  enable_features_data = experiment_data.get('enable_features')
  if enable_features_data:
    experiment['enable_features'] = enable_features_data
  disable_features_data = experiment_data.get('disable_features')
  if disable_features_data:
    experiment['disable_features'] = disable_features_data
  return experiment

def _CreateTrial(study_name, experiment_configs, platform):
  """Returns the applicable experiments for |study_name| and |platform|. This
  iterates through all of the experiment_configs for |study_name| and picks out
  the applicable experiments based off of the valid platforms.
  """
  platform_experiment_lists = [
      config['experiments'] for config in experiment_configs
      if platform in config['platforms']]
  platform_experiments = list(itertools.chain.from_iterable(
      platform_experiment_lists))
  return {
    'name': study_name,
    'experiments': [_CreateExperiment(experiment)
                    for experiment in platform_experiments],
  }

def _GenerateTrials(config, platform):
  for study_name in sorted(config.keys()):
    study = _CreateTrial(study_name, config[study_name], platform)
    # To avoid converting studies with empty experiments (e.g. the study doesn't
    # apply to the target platform), this generator only yields studies that
    # have non-empty experiments.
    if study['experiments']:
      yield study

def ConfigToStudies(config, platform):
  """Returns the applicable studies from config for the platform."""
  return [study for study in _GenerateTrials(config, platform)]

def _FieldTrialConfigToDescription(config, platform):
  return {
    'elements': {
      'kFieldTrialConfig': {
        'studies': ConfigToStudies(config, platform)
      }
    }
  }

def main(arguments):
  parser = optparse.OptionParser(
      description='Generates a struct from a JSON description.',
      usage='usage: %prog [option] -s schema -p platform description')
  parser.add_option('-b', '--destbase',
      help='base directory of generated files.')
  parser.add_option('-d', '--destdir',
      help='directory to output generated files, relative to destbase.')
  parser.add_option('-n', '--namespace',
      help='C++ namespace for generated files. e.g search_providers.')
  parser.add_option('-p', '--platform',
      help='target platform for the field trial, mandatory.')
  parser.add_option('-s', '--schema', help='path to the schema file, '
      'mandatory.')
  parser.add_option('-o', '--output', help='output filename, '
      'mandatory.')
  parser.add_option('-y', '--year',
      help='year to put in the copy-right.')
  (opts, args) = parser.parse_args(args=arguments)

  if not opts.schema:
    parser.error('You must specify a --schema.')

  if not opts.platform:
    parser.error('You must specify a --platform.')

  supported_platforms = ['android', 'chromeos', 'ios', 'linux', 'mac', 'win']
  if opts.platform not in supported_platforms:
    parser.error('\'%s\' is an unknown platform. Supported platforms: %s' %
        (opts.platform, supported_platforms))

  description_filename = os.path.normpath(args[0])
  shortroot = opts.output
  if opts.destdir:
    output_root = os.path.join(os.path.normpath(opts.destdir), shortroot)
  else:
    output_root = shortroot

  if opts.destbase:
    basepath = os.path.normpath(opts.destbase)
  else:
    basepath = ''

  schema = _Load(opts.schema)
  description = _LoadFieldTrialConfig(description_filename, opts.platform)
  json_to_struct.GenerateStruct(
      basepath, output_root, opts.namespace, schema, description,
      os.path.split(description_filename)[1], os.path.split(opts.schema)[1],
      opts.year)

if __name__ == '__main__':
  main(sys.argv[1:])
