# Copyright 2018 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

from telemetry.page import page as page_module


class PressStory(page_module.Page):
  """Base class for Press stories.

  Override ExecuteTest to execute javascript on the page and
  ParseTestResults to obtain javascript metrics from page.

  Example Implementation:

  class FooPressStory:
    URL = 'http://example.com/foo_story'
    NAME = 'FooStory'

    def ExecuteTest(self, action_runner):
      // Execute some javascript

    def ParseTestResults(self, action_runner):
      js_code = 'some_js_expression;'
      self.AddJavaScriptMeasurement(name, unit, js_code)

  """

  URL = None
  DETERMINISTIC_JS = False
  NAME = None

  def __init__(
    self, page_set, tags=None, extra_browser_args=None, url=None, name=None
  ):
    super(PressStory, self).__init__(
      url or self.URL,
      page_set,
      base_dir=page_set.base_dir,
      make_javascript_deterministic=self.DETERMINISTIC_JS,
      name=name or self.NAME or self.URL,
      tags=self.PreprocessTags(tags),
      extra_browser_args=extra_browser_args,
    )
    self._measurements = []
    self._action_runner = None

  def PreprocessTags(self, tags=None):
    if tags is None:
      tags = []
    else:
      assert 'all' not in tags
    tags.append('all')
    return tags

  def AddMeasurement(self, name, unit, samples, description=None):
    """Record an ad-hoc measurement.

    Args:
      name: A string with the name of the measurement (e.g. 'score', 'runtime',
        etc).
      unit: A string specifying the unit used for measurements (e.g. 'ms',
        'count', etc).
      samples: Either a single numeric value or a list of numeric values to
        record as part of this measurement.
      description: An optional string with a short human readable description
        of the measurement.
    """
    # TODO(crbug.com/40642835): Ideally, these should be recorded directly into
    # the results object, rather than held on this temporary list. That needs,
    # however, another slight refactor to make the results object available at
    # this point.
    self._measurements.append(
      {
        'name': name,
        'unit': unit,
        'samples': samples,
        'description': description,
      }
    )

  def AddJavaScriptMeasurement(self, name, unit, code, **kwargs):
    """Run some JavaScript to obtain and record an ad-hoc measurements.

    Args:
      name: A string with the name of the measurement (e.g. 'score', 'runtime',
        etc).
      unit: A string specifying the unit used for measurements (e.g. 'ms',
        'count', etc).
      code: A piece of JavaScript code to run on the current tab, it must
        return either a single or a list of numeric values. These are the
        values for the measurement to be recorded.
      description: An optional string with a short human readable description
        of the measurement.
      Other keyword arguments provide values to be interpolated within
          the JavaScript code. See telemetry.util.js_template for details.
    """
    description = kwargs.pop('description', None)
    samples = self._action_runner.EvaluateJavaScript(code, **kwargs)
    self.AddMeasurement(name, unit, samples, description)

  def GetMeasurements(self):
    return self._measurements

  def Run(self, shared_state):
    self._measurements = []
    super(PressStory, self).Run(shared_state)

  def ExecuteTest(self, action_runner):
    pass

  def ParseTestResults(self, action_runner):
    pass

  def RunPageInteractions(self, action_runner):
    self._action_runner = action_runner
    try:
      self.ExecuteTest(action_runner)
      self.ParseTestResults(action_runner)
    finally:
      self._action_runner = None
