# Copyright (c) 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 collections
import os
import re

import tracing_project
from tracing_build import check_common


class _Token(object):

  def __init__(self, data, token_id=None):
    self.data = data
    if token_id:
      self.token_id = token_id
    else:
      self.token_id = 'plain'


class BuildFile(object):

  def __init__(self, text, file_groups):
    self._file_groups = file_groups
    self._tokens = [token for token in self._Tokenize(text)]

  def _Tokenize(self, text):
    rest = text
    token_regex = self._TokenRegex()
    while len(rest):
      m = token_regex.search(rest)
      if not m:
        # In `rest', we couldn't find a match.
        # So, lump the entire `rest' into a token
        # and stop producing any more tokens.
        yield _Token(rest)
        return
      min_index, end_index, matched_token = self._ProcessMatch(m)

      if min_index > 0:
        yield _Token(rest[:min_index])

      yield matched_token
      rest = rest[end_index:]

  def Update(self, files_by_group):
    for token in self._tokens:
      if token.token_id in files_by_group:
        token.data = self._GetReplacementListAsString(
            token.data,
            files_by_group[token.token_id])

  def Write(self, f):
    for token in self._tokens:
      f.write(token.data)

  def _ProcessMatch(self, match):
    raise NotImplementedError

  def _TokenRegex(self):
    raise NotImplementedError

  def _GetReplacementListAsString(self, existing_list_as_string, filelist):
    raise NotImplementedError


class GypiFile(BuildFile):

  def _ProcessMatch(self, match):
    min_index = match.start(2)
    end_index = match.end(2)
    token = _Token(match.string[min_index:end_index],
                   token_id=match.groups()[0])
    return min_index, end_index, token

  def _TokenRegex(self):
    # regexp to match the following:
    #   'file_group_name': [
    #     'path/to/one/file.extension',
    #     'another/file.ex',
    #   ]
    # In the match,
    # group 1 is : 'file_group_name'
    # group 2 is : """  'path/to/one/file.extension',\n  'another/file.ex',\n"""
    regexp_str = r"'(%s)': \[\n(.+?) +\],?\n" % "|".join(self._file_groups)
    return re.compile(regexp_str, re.MULTILINE | re.DOTALL)

  def _GetReplacementListAsString(self, existing_list_as_string, filelist):
    list_entry = existing_list_as_string.splitlines()[0]
    prefix, _, suffix = list_entry.split("'")
    return "".join(["'".join([prefix, filename, suffix + '\n'])
                    for filename in filelist])


def _GroupFiles(file_name_to_group_name_func, filenames):
  file_groups = collections.defaultdict(lambda: [])
  for filename in filenames:
    file_groups[file_name_to_group_name_func(filename)].append(filename)
  for group in file_groups:
    file_groups[group].sort()
  return file_groups


def _UpdateBuildFile(filename, build_file_class):
  with open(filename, 'r') as f:
    build_file = build_file_class(f.read(), check_common.FILE_GROUPS)
  files_by_group = _GroupFiles(check_common.GetFileGroupFromFileName,
                               check_common.GetKnownFiles())
  build_file.Update(files_by_group)
  with open(filename, 'w') as f:
    build_file.Write(f)


def UpdateGypi():
  tvp = tracing_project.TracingProject()
  _UpdateBuildFile(
      os.path.join(tvp.tracing_root_path, 'trace_viewer.gypi'), GypiFile)


def Update():
  UpdateGypi()