text: #!/usr/bin/env python
  # Copyright 2017 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 blinkbuild.name_style_converter import NameStyleConverter
  import json5_generator
  import template_expander
  import make_style_builder
  import keyword_utils
  from name_utilities import enum_key_for_css_keyword
  
  
  def _find_continuous_segment(numbers):
      """Find the longest continuous segment in a list of numbers.
      For example:
          input:
                  1, 2, 3, 4, 5, 6
                 22,70,23,24,25,26
          output:
              number_list_sorted:
                  1, 3, 4, 5, 6, 2
                 22,23,24,25,26,70
              segments:
                  0, 1, 5, 6
              which means there are 3 segment with start and end indices
              on the number_list_sorted to be: (0, 1), (1, 5), (5, 6)
  
      Args:
          numbers: List of pairs of number
  
      Returns:
          segment: a list containing the indices of the segment start point
              and end point.
          number_list: sorted by the first element version of the input.
  
      """
      segments = [0]
      number_list_sorted = sorted(numbers, key=lambda elem: elem[0])
      for i in range(len(number_list_sorted) - 1):
          # continuous segment is a segment which the number in pair is 1 unit
          # more than the previous pair
          if (number_list_sorted[i + 1][0] - number_list_sorted[i][0] != 1 or
                  number_list_sorted[i + 1][1] - number_list_sorted[i][1] != 1):
              segments.append(i + 1)
      segments.append(len(number_list_sorted))
      return segments, number_list_sorted
  
  
  def _find_largest_segment(segments):
      """Find the largest segment given a list of start and end
      indices of segments
  
      Args:
          segments: a list of start and end indices
  
      Returns:
          longest_segment: the start and end indices of the longest segment
  
      """
      segment_list = zip(segments[:-1], segments[1:])
      return max(segment_list, key=lambda x: x[1] - x[0])
  
  
  def _find_enum_longest_continuous_segment(property_,
                                            name_to_position_dictionary):
      """Find the longest continuous segment in the list of keywords
      Finding the continuous segment will allows us to do the subtraction
      between keywords so that the distance between 2 keywords in this
      enum is equal to the distance of corresponding keywords in another
      enum.
  
      Step 1:
          Convert keyword enums into number.
          Sort and find all continuous segment in the list of enums.
  
      Step 2:
          Get the longest segment.
  
      Step 3:
          Compose a list of keyword enums and their respective numbers
          in the sorted order.
  
      Step 4:
          Build the switch case statements of other enums not in the
          segment. Enums in the segment will be computed in default clause.
      """
      property_enum_order = range(len(property_['keywords']))
      css_enum_order = [
          name_to_position_dictionary[x] for x in property_['keywords']
      ]
      enum_pair_list = zip(css_enum_order, property_enum_order)
      enum_segment, enum_pair_list = _find_continuous_segment(enum_pair_list)
      longest_segment = _find_largest_segment(enum_segment)
  
      enum_tuple_list = []
      for x in enum_pair_list:
          keyword = NameStyleConverter(property_['keywords'][x[1]])
          enum_tuple_list.append((enum_key_for_css_keyword(keyword), x[1], x[0]))
      return enum_tuple_list, enum_segment, longest_segment
  
  
  class CSSValueIDMappingsWriter(make_style_builder.StyleBuilderWriter):
      def __init__(self, json5_file_paths, output_dir):
          super(CSSValueIDMappingsWriter, self).__init__(json5_file_paths,
                                                         output_dir)
          self._outputs = {
              'css_value_id_mappings_generated.h':
              self.generate_css_value_mappings,
          }
          self.css_values_dictionary_file = json5_file_paths[3]
          css_properties = self.css_properties.longhands
          # We sort the enum values based on each value's position in
          # the keywords as listed in css_properties.json5. This will ensure that if there is a continuous
          # segment in css_properties.json5 matching the segment in this enum then
          # the generated enum will have the same order and continuity as
          # css_properties.json5 and we can get the longest continuous segment.
          # Thereby reduce the switch case statement to the minimum.
          css_properties = keyword_utils.sort_keyword_properties_by_canonical_order(
              css_properties, json5_file_paths[3], self.default_parameters)
  
      @template_expander.use_jinja(
          'core/css/templates/css_value_id_mappings_generated.h.tmpl')
      def generate_css_value_mappings(self):
          mappings = {}
          include_paths = set()
          css_values_dictionary = json5_generator.Json5File.load_from_files(
              [self.css_values_dictionary_file],
              default_parameters=self.default_parameters).name_dictionaries
          name_to_position_dictionary = dict(
              zip([x['name'].original for x in css_values_dictionary],
                  range(len(css_values_dictionary))))
  
          for property_ in self.css_properties.properties_including_aliases:
              include_paths.update(property_['include_paths'])
              if property_['field_template'] == 'multi_keyword':
                  mappings[property_['type_name']] = {
                      'default_value':
                      property_['default_value'],
                      'mapping': [
                          enum_key_for_css_keyword(k)
                          for k in property_['keywords']
                      ],
                  }
              elif property_['field_template'] == 'keyword':
                  enum_pair_list, enum_segment, p_segment = _find_enum_longest_continuous_segment(
                      property_, name_to_position_dictionary)
                  mappings[property_['type_name']] = {
                      'default_value': property_['default_value'],
                      'mapping': enum_pair_list,
                      'segment': enum_segment,
                      'longest_segment_length': p_segment[1] - p_segment[0],
                      'start_segment': enum_pair_list[p_segment[0]],
                      'end_segment': enum_pair_list[p_segment[1] - 1],
                  }
  
          return {
              'include_paths': list(sorted(include_paths)),
              'input_files': self._input_files,
              'mappings': mappings,
          }
  
  
  if __name__ == '__main__':
      json5_generator.Maker(CSSValueIDMappingsWriter).main()
  