# 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.

from code import Code
from model import PropertyType

from datetime import datetime

LICENSE = """// Copyright %s 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.
"""

INFO = """// This file was generated by:
//   %s.
"""


class JsUtil(object):
  """A helper class for generating JS Code.
  """
  def GetLicense(self):
    """Returns the license text for JS extern and interface files.
    """
    return (LICENSE % datetime.now().year)

  def GetInfo(self, tool):
    """Returns text describing how the file was generated.
    """
    return (INFO % tool)

  def GenerateObjectDefinition(self, namespace_name, properties):
    """Given an OrderedDict of properties, returns a Code containing the
       description of an object.
    """
    if not properties: return Code()

    c = Code()
    c.Sblock('{')
    first = True
    for field, prop in properties.items():
      # Avoid trailing comma.
      # TODO(devlin): This will be unneeded, if/when
      # https://github.com/google/closure-compiler/issues/796 is fixed.
      if not first:
        c.Append(',', new_line=False)
      first = False
      js_type = self._TypeToJsType(namespace_name, prop.type_)
      if prop.optional:
        js_type = (Code().
                       Append('(').
                       Concat(js_type, new_line=False).
                       Append('|undefined)', new_line=False))
      c.Append('%s: ' % field, strip_right=False)
      c.Concat(js_type, new_line=False)

    c.Eblock('}')

    return c

  def GenerateFunctionJsDoc(self, namespace_name, function):
    """Generates the documentation for a function as a Code.

    Returns an empty code object if the object has no documentation.
    """
    c = Code()
    c.Sblock(line='/**', line_prefix=' * ')

    if function.description:
      c.Comment(function.description, comment_prefix='')

    def append_field(c, tag, js_type, name, optional, description):
      c.Append('@%s {' % tag)
      c.Concat(js_type, new_line=False)
      if optional:
        c.Append('=', new_line=False)
      c.Append('} %s' % name, new_line=False)
      if description:
        c.Comment(' %s' % description, comment_prefix='',
                  wrap_indent=4, new_line=False)

    for param in function.params:
      append_field(c, 'param', self._TypeToJsType(namespace_name, param.type_),
                   param.name, param.optional, param.description)

    if function.callback:
      append_field(c, 'param',
                   self._FunctionToJsFunction(namespace_name,
                                              function.callback),
                   function.callback.name, function.callback.optional,
                   function.callback.description)

    if function.returns:
      append_field(c, 'return',
                   self._TypeToJsType(namespace_name, function.returns),
                   '', False, function.returns.description)

    if function.deprecated:
      c.Append('@deprecated %s' % function.deprecated)

    c.Append(self.GenerateSeeLink(namespace_name, 'method', function.name))

    c.Eblock(' */')
    return c

  def _FunctionToJsFunction(self, namespace_name, function):
    """Converts a model.Function to a JS type (i.e., function([params])...)"""
    c = Code()
    c.Append('function(')
    for i, param in enumerate(function.params):
      c.Concat(self._TypeToJsType(namespace_name, param.type_), new_line=False)
      if i is not len(function.params) - 1:
        c.Append(', ', new_line=False, strip_right=False)
    c.Append('):', new_line=False)

    if function.returns:
      c.Concat(self._TypeToJsType(namespace_name, function.returns),
               new_line=False)
    else:
      c.Append('void', new_line=False)

    return c

  def _TypeToJsType(self, namespace_name, js_type):
    """Converts a model.Type to a JS type (number, Array, etc.)"""
    if js_type.property_type in (PropertyType.INTEGER, PropertyType.DOUBLE):
      return Code().Append('number')
    if js_type.property_type is PropertyType.OBJECT:
      if js_type.properties:
        return self.GenerateObjectDefinition(namespace_name,
                                             js_type.properties)
      return Code().Append('Object')
    if js_type.property_type is PropertyType.ARRAY:
      return (Code().Append('!Array<').
              Concat(self._TypeToJsType(namespace_name, js_type.item_type),
                     new_line=False).
           Append('>', new_line=False))
    if js_type.property_type is PropertyType.REF:
      ref_type = '!chrome.%s.%s' % (namespace_name, js_type.ref_type)
      return Code().Append(ref_type)
    if js_type.property_type is PropertyType.CHOICES:
      c = Code()
      c.Append('(')
      for i, choice in enumerate(js_type.choices):
        c.Concat(self._TypeToJsType(namespace_name, choice), new_line=False)
        if i is not len(js_type.choices) - 1:
          c.Append('|', new_line=False)
      c.Append(')', new_line=False)
      return c
    if js_type.property_type is PropertyType.FUNCTION:
      return self._FunctionToJsFunction(namespace_name, js_type.function)
    if js_type.property_type is PropertyType.ANY:
      return Code().Append('*')
    if js_type.property_type.is_fundamental:
      return Code().Append(js_type.property_type.name)
    return Code().Append('?') # TODO(tbreisacher): Make this more specific.

  def GenerateSeeLink(self, namespace_name, object_type, object_name):
    """Generates a @see link for a given API 'object' (type, method, or event).
    """

    # NOTE(devlin): This is kind of a hack. Some APIs will be hosted on
    # developer.chrome.com/apps/ instead of /extensions/, and some APIs have
    # '.'s in them (like app.window), which should resolve to 'app_window'.
    # Luckily, the doc server has excellent url resolution, and knows exactly
    # what we mean. This saves us from needing any complicated logic here.
    return ('@see https://developer.chrome.com/extensions/%s#%s-%s' %
                (namespace_name, object_type, object_name))
