# Copyright 2013 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.
"""
The Value hierarchy provides a way of representing the values measurements
produce such that they can be merged across runs, grouped by page, and output
to different targets.

The core Value concept provides the basic functionality:
- association with a page, may be none
- naming and units
- importance tracking [whether a value will show up on a waterfall or output
  file by default]
- default conversion to scalar and string
- merging properties

A page may actually run a few times during a single telemetry session.
Downstream consumers of test results typically want to group these runs
together, then compute summary statistics across runs. Value provides the
Merge* family of methods for this kind of aggregation.
"""

# When combining a pair of Values togehter, it is sometimes ambiguous whether
# the values should be concatenated, or one should be picked as representative.
# The possible merging policies are listed here.
CONCATENATE = 'concatenate'
PICK_FIRST = 'pick-first'

# When converting a Value to its buildbot equivalent, the context in which the
# value is being interpreted actually affects the conversion. This is insane,
# but there you have it. There are three contexts in which Values are converted
# for use by buildbot, represented by these output-intent values.
PER_PAGE_RESULT_OUTPUT_CONTEXT = 'per-page-result-output-context'
COMPUTED_PER_PAGE_SUMMARY_OUTPUT_CONTEXT = 'merged-pages-result-output-context'
SUMMARY_RESULT_OUTPUT_CONTEXT = 'summary-result-output-context'

class Value(object):
  """An abstract value produced by a telemetry page test.
  """
  def __init__(self, page, name, units, important):
    """A generic Value object.

    Note: page may be given as None to indicate that the value represents
    results multiple pages.
    """
    self.page = page
    self.name = name
    self.units = units
    self.important = important

  def IsMergableWith(self, that):
    return (self.units == that.units and
            type(self) == type(that) and
            self.important == that.important)

  @classmethod
  def MergeLikeValuesFromSamePage(cls, values):
    """Combines the provided list of values into a single compound value.

    When a page runs multiple times, it may produce multiple values. This
    function is given the same-named values across the multiple runs, and has
    the responsibility of producing a single result.

    It must return a single Value. If merging does not make sense, the
    implementation must pick a representative value from one of the runs.

    For instance, it may be given
        [ScalarValue(page, 'a', 1), ScalarValue(page, 'a', 2)]
    and it might produce
        ListOfScalarValues(page, 'a', [1, 2])
    """
    raise NotImplementedError()

  @classmethod
  def MergeLikeValuesFromDifferentPages(cls, values,
                                        group_by_name_suffix=False):
    """Combines the provided values into a single compound value.

    When a full pageset runs, a single value_name will usually end up getting
    collected for multiple pages. For instance, we may end up with
       [ScalarValue(page1, 'a',  1),
        ScalarValue(page2, 'a',  2)]

    This function takes in the values of the same name, but across multiple
    pages, and produces a single summary result value. In this instance, it
    could produce a ScalarValue(None, 'a', 1.5) to indicate averaging, or even
    ListOfScalarValues(None, 'a', [1, 2]) if concatenated output was desired.

    Some results are so specific to a page that they make no sense when
    aggregated across pages. If merging values of this type across pages is
    non-sensical, this method may return None.

    If group_by_name_suffix is True, then x.z and y.z are considered to be the
    same value and are grouped together. If false, then x.z and y.z are
    considered different.
    """
    raise NotImplementedError()

  def _IsImportantGivenOutputIntent(self, output_context):
    if output_context == PER_PAGE_RESULT_OUTPUT_CONTEXT:
      return False
    elif output_context == COMPUTED_PER_PAGE_SUMMARY_OUTPUT_CONTEXT:
      return self.important
    elif output_context == SUMMARY_RESULT_OUTPUT_CONTEXT:
      return self.important

  def GetBuildbotDataType(self, output_context):
    """Returns the buildbot's equivalent data_type.

    This should be one of the values accepted by perf_tests_results_helper.py.
    """
    raise NotImplementedError()

  def GetBuildbotValue(self):
    """Returns the buildbot's equivalent value."""
    raise NotImplementedError()

  def GetBuildbotMeasurementAndTraceNameForPerPageResult(self):
    measurement, _ = _ConvertValueNameToBuildbotChartAndTraceName(self.name)
    return measurement, self.page.display_name

  @property
  def name_suffix(self):
    """Returns the string after a . in the name, or the full name otherwise."""
    if '.' in self.name:
      return self.name.split('.', 1)[1]
    else:
      return self.name

  def GetBuildbotMeasurementAndTraceNameForComputedSummaryResult(
      self, trace_tag):
    measurement, bb_trace_name = (
        _ConvertValueNameToBuildbotChartAndTraceName(self.name))
    if trace_tag:
      return measurement, bb_trace_name + trace_tag
    else:
      return measurement, bb_trace_name

  def GetRepresentativeNumber(self):
    """Gets a single scalar value that best-represents this value.

    Returns None if not possible.
    """
    raise NotImplementedError()

  def GetRepresentativeString(self):
    """Gets a string value that best-represents this value.

    Returns None if not possible.
    """
    raise NotImplementedError()

  @classmethod
  def GetJSONTypeName(cls):
    """Gets the typename for serialization to JSON using AsDict."""
    raise NotImplementedError()

  def AsDict(self):
    """Gets a representation of this value as a dict for eventual
    serialization to JSON.
    """
    return self._AsDictImpl()

  def _AsDictImpl(self):
    d = {
      'name': self.name,
      'type': self.GetJSONTypeName(),
      'unit': self.units,
    }

    if self.page:
      d['page_id'] = self.page.id

    return d

  def AsDictWithoutBaseClassEntries(self):
    full_dict = self.AsDict()
    base_dict_keys = set(self._AsDictImpl().keys())

    # Exctracts only entries added by the subclass.
    return dict([(k, v) for (k, v) in full_dict.iteritems()
                  if k not in base_dict_keys])

def ValueNameFromTraceAndChartName(trace_name, chart_name=None):
  """Mangles a trace name plus optional chart name into a standard string.

  A value might just be a bareword name, e.g. numPixels. In that case, its
  chart may be None.

  But, a value might also be intended for display with other values, in which
  case the chart name indicates that grouping. So, you might have
  screen.numPixels, screen.resolution, where chartName='screen'.
  """
  assert trace_name != 'url', 'The name url cannot be used'
  if chart_name:
    return '%s.%s' % (chart_name, trace_name)
  else:
    assert '.' not in trace_name, ('Trace names cannot contain "." with an '
        'empty chart_name since this is used to delimit chart_name.trace_name.')
    return trace_name

def _ConvertValueNameToBuildbotChartAndTraceName(value_name):
  """Converts a value_name into the buildbot equivalent name pair.

  Buildbot represents values by the measurement name and an optional trace name,
  whereas telemetry represents values with a chart_name.trace_name convention,
  where chart_name is optional.

  This converts from the telemetry convention to the buildbot convention,
  returning a 2-tuple (measurement_name, trace_name).
  """
  if '.' in value_name:
    return value_name.split('.', 1)
  else:
    return value_name, value_name
