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

"""Helpers for dealing with translation files."""

from __future__ import print_function

import ast
import os
import re
import xml.etree.cElementTree as ElementTree


class GRDFile(object):
  """Class representing a grd xml file.

  Attributes:
    path: the path to the grd file.
    dir: the path to the the grd's parent directery.
    name: the base name of the grd file.
    grdp_paths: the list of grdp files included in the grd via <part>.
    structure_paths: the paths of any <structure> elements in the grd file.
    xtb_paths: the xtb paths where the grd's translations live.
    lang_to_xtb_path: maps each language to the xtb path for that language.
    appears_translatable: whether the contents of the grd indicate that it's
        supposed to be translated.
    expected_languages: the languages that this grd is expected to have
        translations for, based on the translation expectations file.
  """

  def __init__(self, path):
    self.path = path
    self.dir, self.name = os.path.split(path)
    dom, self.grdp_paths = _parse_grd_file(path)
    self.structure_paths = [os.path.join(self.dir, s.get('file'))
                            for s in dom.findall('.//structure')]
    self.xtb_paths = [os.path.join(self.dir, f.get('path'))
                      for f in dom.findall('.//file')]
    self.lang_to_xtb_path = {}
    self.appears_translatable = (len(self.xtb_paths) != 0 or
                                 dom.find('.//message') is not None)
    self.expected_languages = None

  def _populate_lang_to_xtb_path(self, errors):
    """Populates the lang_to_xtb_path attribute."""
    grd_root = os.path.splitext(self.name)[0]
    lang_pattern = re.compile(r'%s_([^_]+)\.xtb$' % re.escape(grd_root))
    for xtb_path in self.xtb_paths:
      xtb_basename = os.path.basename(xtb_path)
      xtb_lang_match = re.match(lang_pattern, xtb_basename)
      if not xtb_lang_match:
        errors.append('%s: invalid xtb name: %s. xtb name must be %s_<lang>'
                      '.xtb where <lang> is the language code.' %
                      (self.name, xtb_basename, grd_root))
        continue
      xtb_lang = xtb_lang_match.group(1)
      if xtb_lang in self.lang_to_xtb_path:
        errors.append('%s: %s is listed twice' % (self.name, xtb_basename))
        continue
      self.lang_to_xtb_path[xtb_lang] = xtb_path

    return errors


def get_translatable_grds(repo_root, all_grd_paths,
                          translation_expectations_path):
  """Returns all the grds that should be translated as a list of GRDFiles.

  This verifies that every grd file that appears translatable is listed in
  the translation expectations, and that every grd in the translation
  expectations actually exists.

  Args:
    repo_root: The path to the root of the repository.
    all_grd_paths: All grd paths in the repository relative to repo_root.
    translation_expectations_path: The path to the translation expectations
        file, which specifies which grds to translate and into which languages.
  """
  parsed_expectations = _parse_translation_expectations(
      translation_expectations_path)
  grd_to_langs, untranslated_grds, internal_grds = parsed_expectations

  errors = []
  # Make sure that grds in internal_grds aren't processed, since they might
  # contain pieces not available publicly.
  for internal_grd in internal_grds:
    try:
      all_grd_paths.remove(internal_grd)
    except ValueError:
      errors.append(
          '%s is listed in translation expectations as an internal file to be '
          'ignored, but this grd file does not exist.' % internal_grd)
  # Check that every grd that appears translatable is listed in
  # the translation expectations.
  grds_with_expectations = set(grd_to_langs.keys()).union(untranslated_grds)
  all_grds = {p: GRDFile(os.path.join(repo_root, p)) for p in all_grd_paths}
  for path, grd in all_grds.iteritems():
    if grd.appears_translatable:
      if path not in grds_with_expectations:
        errors.append('%s appears to be translatable (because it contains '
            '<file> or <message> elements), but is not listed in the '
            'translation expectations.' % path)

  # Check that every file in translation_expectations exists.
  for path in grds_with_expectations:
    if path not in all_grd_paths:
      errors.append('%s is listed in the translation expectations, but this '
          'grd file does not exist.' % path)

  if errors:
    raise Exception('%s needs to be updated. Please fix these issues:\n - %s' %
                    (translation_expectations_path, '\n - '.join(errors)))

  translatable_grds = []
  for path, expected_languages_list in grd_to_langs.iteritems():
    grd = all_grds[path]
    grd.expected_languages = expected_languages_list
    grd._populate_lang_to_xtb_path(errors)
    translatable_grds.append(grd)

    # Ensure each grd lists the expected languages.
    expected_languages = set(expected_languages_list)
    actual_languages = set(grd.lang_to_xtb_path.keys())
    if expected_languages.difference(actual_languages):
      errors.append('%s: missing translations for these languages: %s. Add '
                    '<file> and <output> elements to the grd file, or update '
                    'the translation expectations.' % (grd.name,
                    sorted(expected_languages.difference(actual_languages))))
    if actual_languages.difference(expected_languages):
      errors.append('%s: references translations for unexpected languages: %s. '
                    'Remove the offending <file> and <output> elements from the'
                    ' grd file, or update the translation expectations.'
                    % (grd.name,
                    sorted(actual_languages.difference(expected_languages))))

  if errors:
    raise Exception('Please fix these issues:\n - %s' %
                    ('\n - '.join(errors)))

  return translatable_grds


def _parse_grd_file(grd_path):
  """Reads a grd(p) file and any subfiles included via <part file="..." />.

  Args:
    grd_path: The path of the .grd or .grdp file.
  Returns:
    A tuple (grd_dom, grdp_paths). dom is an ElementTree DOM for the grd file,
    with the <part> elements inlined. grdp_paths is the list of grdp files that
    were included via <part> elements.
  """
  grdp_paths = []
  grd_dom = ElementTree.parse(grd_path)
  # We modify grd in the loop, so listify this iterable to be safe.
  part_nodes = list(grd_dom.findall('.//part'))
  for part_node in part_nodes:
    grdp_rel_path = part_node.get('file')
    grdp_path = os.path.join(os.path.dirname(grd_path), grdp_rel_path)
    grdp_paths.append(grdp_path)
    grdp_dom, grdp_grdp_paths = _parse_grd_file(grdp_path)
    grdp_paths.extend(grdp_grdp_paths)
    part_node.append(grdp_dom.getroot())
  return grd_dom, grdp_paths


def _parse_translation_expectations(path):
  """Parses a translations expectations file.

  Example translations expectations file:
  {
    "desktop_grds": {
      "languages": ["es", "fr"],
      "files": [
        "ash/ash_strings.grd",
        "ui/strings/ui_strings.grd",
      ],
    },
    "android_grds": {
      "languages": ["de", "pt-BR"],
      "files": [
        "chrome/android/android_chrome_strings.grd",
      ],
    },
    "untranslated_grds": {
      "chrome/locale_settings.grd": "Not UI strings; localized separately",
      "chrome/locale_settings_mac.grd": "Not UI strings; localized separately",
    },
    "internal_grds": [
      "chrome/internal.grd",
    ],
  }

  Returns:
    A tuple (grd_to_langs, untranslated_grds, internal_grds).
    grd_to_langs maps each grd path to the list of languages into which
    that grd should be translated. untranslated_grds is a list of grds
    that "appear translatable" but should not be translated.
    internal_grds is a list of grds that are internal only and should
    not be read by this helper (since they might contain parts not
    available publicly).
  """
  with open(path) as f:
    file_contents = f.read()

  def assert_list_of_strings(l, name):
    assert isinstance(l, list) and all(isinstance(s, basestring) for s in l), (
        '%s must be a list of strings' % name)

  try:
    translations_expectations = ast.literal_eval(file_contents)
    assert isinstance(translations_expectations, dict), (
        '%s must be a python dict' % path)

    grd_to_langs = {}
    untranslated_grds = []
    internal_grds = []

    for group_name, settings in translations_expectations.items():
      if group_name == 'untranslated_grds':
        untranslated_grds = list(settings.keys())
        assert_list_of_strings(untranslated_grds, 'untranslated_grds')
        continue

      if group_name == 'internal_grds':
        internal_grds = settings
        assert_list_of_strings(internal_grds, 'internal_grds')
        continue

      languages = settings['languages']
      files = settings['files']
      assert_list_of_strings(languages, group_name + '.languages')
      assert_list_of_strings(files, group_name + '.files')
      for grd in files:
        grd_to_langs[grd] = languages

    return grd_to_langs, untranslated_grds, internal_grds

  except Exception:
    print('Error: failed to parse', path)
    raise
