#!/usr/bin/env python
# Copyright (c) 2012 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.
"""Generator for C++ structs from api json files.

The purpose of this tool is to remove the need for hand-written code that
converts to and from base::Value types when receiving javascript api calls.
Originally written for generating code for extension apis. Reference schemas
are in chrome/common/extensions/api.

Usage example:
  compiler.py --root /home/Work/src --namespace extensions windows.json
    tabs.json
  compiler.py --destdir gen --root /home/Work/src
    --namespace extensions windows.json tabs.json
"""

import optparse
import os
import shlex
import sys

from cpp_bundle_generator import CppBundleGenerator
from cpp_generator import CppGenerator
from cpp_type_generator import CppTypeGenerator
from dart_generator import DartGenerator
import json_schema
from cpp_namespace_environment import CppNamespaceEnvironment
from model import Model
from schema_loader import SchemaLoader

# Names of supported code generators, as specified on the command-line.
# First is default.
GENERATORS = ['cpp', 'cpp-bundle-registration', 'cpp-bundle-schema', 'dart']

def GenerateSchema(generator_name,
                   file_paths,
                   root,
                   destdir,
                   cpp_namespace_pattern,
                   dart_overrides_dir,
                   impl_dir,
                   include_rules):
  # Merge the source files into a single list of schemas.
  api_defs = []
  for file_path in file_paths:
    schema = os.path.relpath(file_path, root)
    schema_loader = SchemaLoader(
        root,
        os.path.dirname(schema),
        include_rules,
        cpp_namespace_pattern)
    api_def = schema_loader.LoadSchema(schema)

    # If compiling the C++ model code, delete 'nocompile' nodes.
    if generator_name == 'cpp':
      api_def = json_schema.DeleteNodes(api_def, 'nocompile')
    api_defs.extend(api_def)

  api_model = Model()

  # For single-schema compilation make sure that the first (i.e. only) schema
  # is the default one.
  default_namespace = None

  # If we have files from multiple source paths, we'll use the common parent
  # path as the source directory.
  src_path = None

  # Load the actual namespaces into the model.
  for target_namespace, file_path in zip(api_defs, file_paths):
    relpath = os.path.relpath(os.path.normpath(file_path), root)
    namespace = api_model.AddNamespace(target_namespace,
                                       relpath,
                                       include_compiler_options=True,
                                       environment=CppNamespaceEnvironment(
                                           cpp_namespace_pattern))

    if default_namespace is None:
      default_namespace = namespace

    if src_path is None:
      src_path = namespace.source_file_dir
    else:
      src_path = os.path.commonprefix((src_path, namespace.source_file_dir))

    path, filename = os.path.split(file_path)
    filename_base, _ = os.path.splitext(filename)

  # Construct the type generator with all the namespaces in this model.
  type_generator = CppTypeGenerator(api_model,
                                    schema_loader,
                                    default_namespace)
  if generator_name in ('cpp-bundle-registration', 'cpp-bundle-schema'):
    cpp_bundle_generator = CppBundleGenerator(root,
                                              api_model,
                                              api_defs,
                                              type_generator,
                                              cpp_namespace_pattern,
                                              src_path,
                                              impl_dir)
    if generator_name == 'cpp-bundle-registration':
      generators = [
        ('generated_api_registration.cc',
         cpp_bundle_generator.api_cc_generator),
        ('generated_api_registration.h', cpp_bundle_generator.api_h_generator),
      ]
    elif generator_name == 'cpp-bundle-schema':
      generators = [
        ('generated_schemas.cc', cpp_bundle_generator.schemas_cc_generator),
        ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator)
      ]
  elif generator_name == 'cpp':
    cpp_generator = CppGenerator(type_generator)
    generators = [
      ('%s.h' % filename_base, cpp_generator.h_generator),
      ('%s.cc' % filename_base, cpp_generator.cc_generator)
    ]
  elif generator_name == 'dart':
    generators = [
      ('%s.dart' % namespace.unix_name, DartGenerator(
          dart_overrides_dir))
    ]
  else:
    raise Exception('Unrecognised generator %s' % generator)

  output_code = []
  for filename, generator in generators:
    code = generator.Generate(namespace).Render()
    if destdir:
      if generator_name == 'cpp-bundle-registration':
        # Function registrations must be output to impl_dir, since they link in
        # API implementations.
        output_dir = os.path.join(destdir, impl_dir)
      else:
        output_dir = os.path.join(destdir, src_path)
      if not os.path.exists(output_dir):
        os.makedirs(output_dir)
      with open(os.path.join(output_dir, filename), 'w') as f:
        f.write(code)
    output_code += [filename, '', code, '']

  return '\n'.join(output_code)


if __name__ == '__main__':
  parser = optparse.OptionParser(
      description='Generates a C++ model of an API from JSON schema',
      usage='usage: %prog [option]... schema')
  parser.add_option('-r', '--root', default='.',
      help='logical include root directory. Path to schema files from specified'
      ' dir will be the include path.')
  parser.add_option('-d', '--destdir',
      help='root directory to output generated files.')
  parser.add_option('-n', '--namespace', default='generated_api_schemas',
      help='C++ namespace for generated files. e.g extensions::api.')
  parser.add_option('-g', '--generator', default=GENERATORS[0],
      choices=GENERATORS,
      help='The generator to use to build the output code. Supported values are'
      ' %s' % GENERATORS)
  parser.add_option('-D', '--dart-overrides-dir', dest='dart_overrides_dir',
      help='Adds custom dart from files in the given directory (Dart only).')
  parser.add_option('-i', '--impl-dir', dest='impl_dir',
      help='The root path of all API implementations')
  parser.add_option('-I', '--include-rules',
      help='A list of paths to include when searching for referenced objects,'
      ' with the namespace separated by a \':\'. Example: '
      '/foo/bar:Foo::Bar::%(namespace)s')

  (opts, file_paths) = parser.parse_args()

  if not file_paths:
    sys.exit(0) # This is OK as a no-op

  # Unless in bundle mode, only one file should be specified.
  if (opts.generator not in ('cpp-bundle-registration', 'cpp-bundle-schema') and
      len(file_paths) > 1):
    # TODO(sashab): Could also just use file_paths[0] here and not complain.
    raise Exception(
        "Unless in bundle mode, only one file can be specified at a time.")

  def split_path_and_namespace(path_and_namespace):
    if ':' not in path_and_namespace:
      raise ValueError('Invalid include rule "%s". Rules must be of '
                       'the form path:namespace' % path_and_namespace)
    return path_and_namespace.split(':', 1)

  include_rules = []
  if opts.include_rules:
    include_rules = map(split_path_and_namespace,
                        shlex.split(opts.include_rules))

  result = GenerateSchema(opts.generator, file_paths, opts.root, opts.destdir,
                          opts.namespace, opts.dart_overrides_dir,
                          opts.impl_dir, include_rules)
  if not opts.destdir:
    print result
