# Copyright 2014 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 telemetry.page import page as page_module
from telemetry.page import page_set as page_set_module


class KeySilkCasesPage(page_module.Page):

  def __init__(self, url, page_set):
    super(KeySilkCasesPage, self).__init__(url=url, page_set=page_set)
    self.credentials_path = 'data/credentials.json'
    self.user_agent_type = 'mobile'
    self.archive_data_file = 'data/key_silk_cases.json'

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.Wait(2)

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollPage()
    interaction.End()


class Page1(KeySilkCasesPage):

  """ Why: Infinite scroll. Brings out all of our perf issues. """

  def __init__(self, page_set):
    super(Page1, self).__init__(
      url='http://groupcloned.com/test/plain/list-recycle-transform.html',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollElement(selector='#scrollable')
    interaction.End()


class Page2(KeySilkCasesPage):

  """ Why: Brings out layer management bottlenecks. """

  def __init__(self, page_set):
    super(Page2, self).__init__(
      url='http://groupcloned.com/test/plain/list-animation-simple.html',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    action_runner.Wait(2)


class Page3(KeySilkCasesPage):

  """
  Why: Best-known method for fake sticky. Janks sometimes. Interacts badly with
  compositor scrolls.
  """

  def __init__(self, page_set):
    super(Page3, self).__init__(
      # pylint: disable=C0301
      url='http://groupcloned.com/test/plain/sticky-using-webkit-backface-visibility.html',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollElement(selector='#container')
    interaction.End()


class Page4(KeySilkCasesPage):

  """
  Why: Card expansion: only the card should repaint, but in reality lots of
  storms happen.
  """

  def __init__(self, page_set):
    super(Page4, self).__init__(
      url='http://jsfiddle.net/3yDKh/15/show/',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    action_runner.Wait(3)


class Page5(KeySilkCasesPage):

  """
  Why: Card expansion with animated contents, using will-change on the card
  """

  def __init__(self, page_set):
    super(Page5, self).__init__(
      url='http://jsfiddle.net/jx5De/14/show/',
      page_set=page_set)

    self.gpu_raster = True

  def RunSmoothness(self, action_runner):
    action_runner.Wait(4)


class Page6(KeySilkCasesPage):

  """
  Why: Card fly-in: It should be fast to animate in a bunch of cards using
  margin-top and letting layout do the rest.
  """

  def __init__(self, page_set):
    super(Page6, self).__init__(
      url='http://jsfiddle.net/3yDKh/16/show/',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    action_runner.Wait(3)


class Page7(KeySilkCasesPage):

  """
  Why: Image search expands a spacer div when you click an image to accomplish
  a zoomin effect. Each image has a layer. Even so, this triggers a lot of
  unnecessary repainting.
  """

  def __init__(self, page_set):
    super(Page7, self).__init__(
      url='http://jsfiddle.net/R8DX9/4/show/',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    action_runner.Wait(3)


class Page8(KeySilkCasesPage):

  """
  Why: Swipe to dismiss of an element that has a fixed-position child that is
  its pseudo-sticky header. Brings out issues with layer creation and
  repainting.
  """

  def __init__(self, page_set):
    super(Page8, self).__init__(
      url='http://jsfiddle.net/rF9Gh/7/show/',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    action_runner.Wait(3)


class Page9(KeySilkCasesPage):

  """
  Why: Horizontal and vertical expansion of a card that is cheap to layout but
  costly to rasterize.
  """

  def __init__(self, page_set):
    super(Page9, self).__init__(
      url='http://jsfiddle.net/TLXLu/3/show/',
      page_set=page_set)

    self.gpu_raster = True

  def RunSmoothness(self, action_runner):
    action_runner.Wait(4)


class Page10(KeySilkCasesPage):

  """
  Why: Vertical Expansion of a card that is cheap to layout but costly to
  rasterize.
  """

  def __init__(self, page_set):
    super(Page10, self).__init__(
      url='http://jsfiddle.net/cKB9D/7/show/',
      page_set=page_set)

    self.gpu_raster = True

  def RunSmoothness(self, action_runner):
    action_runner.Wait(4)


class Page11(KeySilkCasesPage):

  """
  Why: Parallax effect is common on photo-viewer-like applications, overloading
  software rasterization
  """

  def __init__(self, page_set):
    super(Page11, self).__init__(
      url='http://jsfiddle.net/vBQHH/11/show/',
      page_set=page_set)

    self.gpu_raster = True

  def RunSmoothness(self, action_runner):
    action_runner.Wait(4)


class Page12(KeySilkCasesPage):

  """ Why: Addressing paint storms during coordinated animations. """

  def __init__(self, page_set):
    super(Page12, self).__init__(
      url='http://jsfiddle.net/ugkd4/10/show/',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    action_runner.Wait(5)


class Page13(KeySilkCasesPage):

  """ Why: Mask transitions are common mobile use cases. """

  def __init__(self, page_set):
    super(Page13, self).__init__(
      url='http://jsfiddle.net/xLuvC/1/show/',
      page_set=page_set)

    self.gpu_raster = True

  def RunSmoothness(self, action_runner):
    action_runner.Wait(4)


class Page14(KeySilkCasesPage):

  """ Why: Card expansions with images and text are pretty and common. """

  def __init__(self, page_set):
    super(Page14, self).__init__(
      url='http://jsfiddle.net/bNp2h/3/show/',
      page_set=page_set)

    self.gpu_raster = True

  def RunSmoothness(self, action_runner):
    action_runner.Wait(4)


class Page15(KeySilkCasesPage):

  """ Why: Coordinated animations for expanding elements. """

  def __init__(self, page_set):
    super(Page15, self).__init__(
      url='file://key_silk_cases/font_wipe.html',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    action_runner.Wait(5)


class Page16(KeySilkCasesPage):

  def __init__(self, page_set):
    super(Page16, self).__init__(
      url='file://key_silk_cases/inbox_app.html?swipe_to_dismiss',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.Wait(2)

  def SwipeToDismiss(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'SwipeAction', is_smooth=True)
    action_runner.SwipeElement(
        left_start_ratio=0.8, top_start_ratio=0.2,
        direction='left', distance=200, speed_in_pixels_per_second=5000,
        element_function='document.getElementsByClassName("message")[2]')
    interaction.End()
    interaction = action_runner.BeginInteraction('Wait', is_smooth=True)
    action_runner.WaitForJavaScriptCondition(
        'document.getElementsByClassName("message").length < 18')
    interaction.End()

  def RunSmoothness(self, action_runner):
    self.SwipeToDismiss(action_runner)


class Page17(KeySilkCasesPage):

  def __init__(self, page_set):
    super(Page17, self).__init__(
      url='file://key_silk_cases/inbox_app.html?stress_hidey_bars',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.Wait(2)

  def RunSmoothness(self, action_runner):
    self.StressHideyBars(action_runner)

  def StressHideyBars(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollElement(
        selector='#messages', direction='down', speed_in_pixels_per_second=200)
    interaction.End()
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollElement(
        selector='#messages', direction='up', speed_in_pixels_per_second=200)
    interaction.End()
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollElement(
        selector='#messages', direction='down', speed_in_pixels_per_second=200)
    interaction.End()


class Page18(KeySilkCasesPage):

  def __init__(self, page_set):
    super(Page18, self).__init__(
      url='file://key_silk_cases/inbox_app.html?toggle_drawer',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.Wait(2)

  def RunSmoothness(self, action_runner):
    for _ in xrange(6):
      self.ToggleDrawer(action_runner)

  def ToggleDrawer(self, action_runner):
    interaction = action_runner.BeginInteraction(
        'Action_TapAction', is_smooth=True)
    action_runner.TapElement('#menu-button')
    action_runner.Wait(1)
    interaction.End()


class Page19(KeySilkCasesPage):

  def __init__(self, page_set):
    super(Page19, self).__init__(
      url='file://key_silk_cases/inbox_app.html?slide_drawer',
      page_set=page_set)

  def ToggleDrawer(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'TapAction', is_smooth=True)
    action_runner.TapElement('#menu-button')
    interaction.End()

    interaction = action_runner.BeginInteraction('Wait', is_smooth=True)
    action_runner.WaitForJavaScriptCondition('''
        document.getElementById("nav-drawer").active &&
        document.getElementById("nav-drawer").children[0]
            .getBoundingClientRect().left == 0''')
    interaction.End()

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.Wait(2)
    self.ToggleDrawer(action_runner)

  def RunSmoothness(self, action_runner):
    self.SlideDrawer(action_runner)

  def SlideDrawer(self, action_runner):
    interaction = action_runner.BeginInteraction(
        'Action_SwipeAction', is_smooth=True)
    action_runner.SwipeElement(
        left_start_ratio=0.8, top_start_ratio=0.2,
        direction='left', distance=200,
        element_function='document.getElementById("nav-drawer").children[0]')
    action_runner.WaitForJavaScriptCondition(
        '!document.getElementById("nav-drawer").active')
    interaction.End()


class Page20(KeySilkCasesPage):

  """ Why: Shadow DOM infinite scrolling. """

  def __init__(self, page_set):
    super(Page20, self).__init__(
      url='file://key_silk_cases/infinite_scrolling.html',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollElement(
        selector='#container', speed_in_pixels_per_second=5000)
    interaction.End()


class GwsExpansionPage(KeySilkCasesPage):
  """Abstract base class for pages that expand Google knowledge panels."""

  def NavigateWait(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.Wait(3)

  def ExpandKnowledgeCard(self, action_runner):
    # expand card
    interaction = action_runner.BeginInteraction(
        'Action_TapAction', is_smooth=True)
    action_runner.TapElement(
        element_function='document.getElementsByClassName("vk_arc")[0]')
    action_runner.Wait(2)
    interaction.End()

  def ScrollKnowledgeCardToTop(self, action_runner, card_id):
    # scroll until the knowledge card is at the top
    action_runner.ExecuteJavaScript(
        "document.getElementById('%s').scrollIntoView()" % card_id)

  def RunSmoothness(self, action_runner):
    self.ExpandKnowledgeCard(action_runner)


class GwsGoogleExpansion(GwsExpansionPage):

  """ Why: Animating height of a complex content card is common. """

  def __init__(self, page_set):
    super(GwsGoogleExpansion, self).__init__(
      url='http://www.google.com/#q=google',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    self.NavigateWait(action_runner)
    self.ScrollKnowledgeCardToTop(action_runner, 'kno-result')


class GwsBoogieExpansion(GwsExpansionPage):

  """ Why: Same case as Google expansion but text-heavy rather than image. """

  def __init__(self, page_set):
    super(GwsBoogieExpansion, self).__init__(
      url='https://www.google.com/search?hl=en&q=define%3Aboogie',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    self.NavigateWait(action_runner)
    self.ScrollKnowledgeCardToTop(action_runner, 'rso')


class Page22(KeySilkCasesPage):

  def __init__(self, page_set):
    super(Page22, self).__init__(
      url='http://plus.google.com/app/basic/stream',
      page_set=page_set)

    self.disabled = 'Times out on Windows; crbug.com/338838'
    self.credentials = 'google'

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.WaitForJavaScriptCondition(
        'document.getElementsByClassName("fHa").length > 0')
    action_runner.Wait(2)

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollElement(selector='#mainContent')
    interaction.End()


class Page23(KeySilkCasesPage):

  """
  Why: Physical simulation demo that does a lot of element.style mutation
  triggering JS and recalc slowness
  """

  def __init__(self, page_set):
    super(Page23, self).__init__(
      url='http://jsbin.com/UVIgUTa/38/quiet',
      page_set=page_set)

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollPage(
        distance_expr='window.innerHeight / 2',
        direction='down',
        use_touch=True)
    interaction.End()
    interaction = action_runner.BeginInteraction('Wait', is_smooth=True)
    action_runner.Wait(1)
    interaction.End()


class Page24(KeySilkCasesPage):

  """
  Why: Google News: this iOS version is slower than accelerated scrolling
  """

  def __init__(self, page_set):
    super(Page24, self).__init__(
      url='http://mobile-news.sandbox.google.com/news/pt0?scroll',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.WaitForJavaScriptCondition(
        'document.getElementById(":h") != null')
    action_runner.Wait(1)

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollElement(
        element_function='document.getElementById(":5")',
        distance=2500,
        use_touch=True)
    interaction.End()


class Page25(KeySilkCasesPage):

  def __init__(self, page_set):
    super(Page25, self).__init__(
      url='http://mobile-news.sandbox.google.com/news/pt0?swipe',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.WaitForJavaScriptCondition(
        'document.getElementById(":h") != null')
    action_runner.Wait(1)

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'SwipeAction', is_smooth=True)
    action_runner.SwipeElement(
        direction='left', distance=100,
        element_function='document.getElementById(":f")')
    interaction.End()
    interaction = action_runner.BeginInteraction('Wait', is_smooth=True)
    action_runner.Wait(1)
    interaction.End()


class Page26(KeySilkCasesPage):

  """ Why: famo.us twitter demo """

  def __init__(self, page_set):
    super(Page26, self).__init__(
      url='http://s.codepen.io/befamous/fullpage/pFsqb?scroll',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.WaitForJavaScriptCondition(
        'document.getElementsByClassName("tweet").length > 0')
    action_runner.Wait(1)

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginGestureInteraction(
        'ScrollAction', is_smooth=True)
    action_runner.ScrollPage(distance=5000)
    interaction.End()


class SVGIconRaster(KeySilkCasesPage):

  """ Why: Mutating SVG icons; these paint storm and paint slowly. """

  def __init__(self, page_set):
    super(SVGIconRaster, self).__init__(
      url='http://wiltzius.github.io/shape-shifter/',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.WaitForJavaScriptCondition(
        'loaded = true')
    action_runner.Wait(1)

  def RunSmoothness(self, action_runner):
    for i in xrange(9):
      button_func = ('document.getElementById("demo").$.'
                     'buttons.children[%d]') % i
      interaction = action_runner.BeginInteraction(
            'Action_TapAction', is_smooth=True)
      action_runner.TapElement(element_function=button_func)
      action_runner.Wait(1)
      interaction.End()


class UpdateHistoryState(KeySilkCasesPage):

  """ Why: Modern apps often update history state, which currently is janky."""

  def __init__(self, page_set):
    super(UpdateHistoryState, self).__init__(
      url='file://key_silk_cases/pushState.html',
      page_set=page_set)

  def RunNavigateSteps(self, action_runner):
    action_runner.NavigateToPage(self)
    action_runner.ExecuteJavaScript('''
        window.requestAnimationFrame(function() {
            window.__history_state_loaded = true;
          });
        ''')
    action_runner.WaitForJavaScriptCondition(
        'window.__history_state_loaded == true;')

  def RunSmoothness(self, action_runner):
    interaction = action_runner.BeginInteraction('animation_interaction',
        is_smooth=True)
    action_runner.Wait(5) # JS runs the animation continuously on the page
    interaction.End()


class TextSizeAnimation(KeySilkCasesPage):

  """ Why: Scale animation with text. """

  def __init__(self, page_set):
    super(TextSizeAnimation, self).__init__(
      url='http://jsbin.com/gikex/2/quiet',
      page_set=page_set)

    self.gpu_raster = True

  def RunSmoothness(self, action_runner):
    action_runner.Wait(4)


class KeySilkCasesPageSet(page_set_module.PageSet):

  """ Pages hand-picked for project Silk. """

  def __init__(self):
    super(KeySilkCasesPageSet, self).__init__(
      credentials_path='data/credentials.json',
      user_agent_type='mobile',
      archive_data_file='data/key_silk_cases.json',
      bucket=page_set_module.PARTNER_BUCKET)

    self.AddPage(Page1(self))
    self.AddPage(Page2(self))
    self.AddPage(Page3(self))
    self.AddPage(Page4(self))
    self.AddPage(Page5(self))
    self.AddPage(Page6(self))
    self.AddPage(Page7(self))
    self.AddPage(Page8(self))
    self.AddPage(Page9(self))
    self.AddPage(Page10(self))
    self.AddPage(Page11(self))
    self.AddPage(Page12(self))
    self.AddPage(Page13(self))
    self.AddPage(Page14(self))
    self.AddPage(Page15(self))
    self.AddPage(Page16(self))
    self.AddPage(Page17(self))
    self.AddPage(Page18(self))
    # crbug.com/404317
    # self.AddPage(Page19(self))
    self.AddPage(Page20(self))
    self.AddPage(GwsGoogleExpansion(self))
    self.AddPage(GwsBoogieExpansion(self))
    self.AddPage(Page22(self))
    self.AddPage(Page23(self))
    self.AddPage(Page24(self))
    self.AddPage(Page25(self))
    self.AddPage(Page26(self))
    self.AddPage(SVGIconRaster(self))
    self.AddPage(UpdateHistoryState(self))
    self.AddPage(TextSizeAnimation(self))
