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

"""A factory test to test the functionality of a mouse/trackpoint.

Description
-----------
A mouse/trackpoint test for moving and clicking.

Test Procedure
--------------
1. Move the mouse in all 4 directions. The corresponding grid will become green
   once you move in that direction. The moving speed must be greater than
   `move_threshold` for the test to detect the moving direction of the mouse.
2. Click the left, middle and right button of the mouse. The corresponding grid
   will become green once you click the button.

If you don't pass the test in `timeout_secs` seconds, the test will fail.

Dependency
----------
- Based on Linux evdev.

Examples
--------
To test mouse/trackpoint with default parameters, add this in test list::

  {
    "pytest_name": "mouse"
  }

If you want to change the time limit to 100 seconds::

  {
    "pytest_name": "mouse",
    "args": {
      "timeout_secs": 100
    }
  }
"""

import logging
import time

from cros.factory.test import test_case
from cros.factory.test.utils import evdev_utils
from cros.factory.utils.arg_utils import Arg
from cros.factory.utils import process_utils

from cros.factory.external.py_lib import evdev


class MouseTest(test_case.TestCase):
  """Tests the function of a mouse/trackpoint."""
  related_components = tuple()

  ARGS = [
      Arg('device_filter', (int, str),
          ('Mouse input event id or evdev name. The test will probe for '
           'event id if it is not given.'), default=None),
      Arg('timeout_secs', int, 'Timeout for thte test.', default=20),
      Arg('button_updown_secs', float,
          'Max duration between button up and down.', default=0.6),
      Arg('move_threshold', int, 'Speed threshold to detect the move direction',
          default=3)
  ]

  def setUp(self):
    # yapf: disable
    self.assertGreater(self.args.move_threshold, 0,  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
    # yapf: enable
                       'move_threshold must be greater than 0.')
    self.mouse_device = evdev_utils.FindDevice(
        # yapf: disable
        self.args.device_filter, evdev_utils.IsMouseDevice)  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
    # yapf: enable
    self.mouse_device_name = self.mouse_device.name

    self.frontend_proxy = None
    self.dispatcher = None
    self.down_keycode_time = {}

    self.move_tested = {
        'up': False,
        'down': False,
        'left': False,
        'right': False}
    self.click_tested = {
        'left': False,
        'middle': False,
        'right': False
    }
    # Disable lid function since lid open|close will trigger button up event.
    process_utils.CheckOutput(['ectool', 'forcelidopen', '1'])

  def tearDown(self):
    # yapf: disable
    self.dispatcher.Close()  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
    # yapf: enable
    self.mouse_device.ungrab()
    # Enable lid function.
    process_utils.CheckOutput(['ectool', 'forcelidopen', '0'])

  def HandleEvent(self, event):
    """Handler for evdev events."""
    # yapf: disable
    if event.type == evdev.ecodes.EV_KEY:  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
      # yapf: enable
      self.OnClickButton(event.code, event.value)
    # yapf: disable
    elif event.type == evdev.ecodes.EV_REL:  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
      # yapf: enable
      self.OnMoveDirection(event.code, event.value)

  def OnClickButton(self, keycode, value):
    button_map = {
        # yapf: disable
        evdev.ecodes.BTN_LEFT: 'left',  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
        # yapf: enable
        # yapf: disable
        evdev.ecodes.BTN_MIDDLE: 'middle',  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
        # yapf: enable
        # yapf: disable
        evdev.ecodes.BTN_RIGHT: 'right'  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
        # yapf: enable
    }
    button = button_map[keycode]
    if value == 1:
      if self.down_keycode_time:
        self.FailTask('More than one button clicked')
      self.down_keycode_time[keycode] = time.time()
      # yapf: disable
      self.frontend_proxy.MarkClickButtonDown(button)  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
      # yapf: enable
    else:
      duration = time.time() - self.down_keycode_time[keycode]
      # yapf: disable
      if duration > self.args.button_updown_secs:  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
        # yapf: enable
        self.FailTask(
            # yapf: disable
            f'The time between button up and down is {duration:f} second(s), '  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
            # yapf: enable
            f'longer than {self.args.button_updown_secs:f} second(s).')
      del self.down_keycode_time[keycode]
      # yapf: disable
      self.frontend_proxy.MarkClickButtonTested(button)  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
      # yapf: enable
      self.click_tested[button] = True
      self.CheckTestPassed()

  def OnMoveDirection(self, keycode, value):
    # yapf: disable
    if abs(value) < self.args.move_threshold:  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
      # yapf: enable
      return
    # yapf: disable
    if keycode == evdev.ecodes.REL_X:  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
      # yapf: enable
      direction = 'right' if value > 0 else 'left'
    # yapf: disable
    elif keycode == evdev.ecodes.REL_Y:  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
      # yapf: enable
      direction = 'down' if value > 0 else 'up'
    else:
      logging.warning('Unknown keycode: %d', keycode)
      return

    # yapf: disable
    self.frontend_proxy.MarkMoveDirectionTested(direction)  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
    # yapf: enable
    self.move_tested[direction] = True
    self.CheckTestPassed()

  def CheckTestPassed(self):
    """Check if all items have been tested."""
    if all(self.click_tested.values()) and all(self.move_tested.values()):
      self.PassTask()

  def FailTestTimeout(self):
    """Fail the test due to timeout, and log untested functions."""
    failed_move = [
        direction for direction, tested in self.move_tested.items()
        if not tested]
    failed_click = [
        button for button, tested in self.click_tested.items() if not tested
    ]
    self.FailTask(
        f'Test timed out. Malfunction move directions: {failed_move!r}. '
        f'Malfunction buttons: {failed_click!r}')

  def runTest(self):
    self.mouse_device.grab()

    # yapf: disable
    self.ui.StartCountdownTimer(self.args.timeout_secs, self.FailTestTimeout)  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
    # yapf: enable
    # yapf: disable
    self.frontend_proxy = self.ui.InitJSTestObject('MouseTest')  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
    # yapf: enable

    self.dispatcher = evdev_utils.InputDeviceDispatcher(
        self.mouse_device,
        # yapf: disable
        self.event_loop.CatchException(self.HandleEvent))  # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
    # yapf: enable
    logging.info('start monitor daemon thread')
    self.dispatcher.StartDaemon()

    self.WaitTaskEnd()
