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

import os

from autotest_lib.client.bin import test
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.cros.input_playback import input_playback


class a11y_test_base(test.test):
    """Base class for a11y tests."""
    version = 1

    # ChromeVox extension id
    _CHROMEVOX_ID = 'mndnfokpggljbaajbnioimlmbfngpief'
    _CVOX_STATE_TIMEOUT = 40
    _CVOX_INDICATOR_TIMEOUT = 40


    def warmup(self):
        """Test setup."""
        # Emulate a keyboard for later ChromeVox toggle (if needed).
        # See input_playback. The keyboard is used to play back shortcuts.
        self._player = input_playback.InputPlayback()
        self._player.emulate(input_type='keyboard')
        self._player.find_connected_inputs()


    def _child_test_cleanup(self):
        """Can be overwritten by child classes and run duing parent cleanup."""
        return


    def cleanup(self):
        self._player.close()
        self._child_test_cleanup()


    def _toggle_chromevox(self):
        """Use keyboard shortcut and emulated keyboard to toggle ChromeVox."""
        self._player.blocking_playback_of_default_file(
                input_type='keyboard', filename='keyboard_ctrl+alt+z')


    def _search_shift_move(self, direction):
        """Playback the keyboard movement shortcut for given direction.

        @param direction: right, left, up, or down.

        """
        assert direction in ['right', 'left', 'up', 'down']
        self._player.blocking_playback_of_default_file(
                input_type='keyboard',
                filename='keyboard_search+shift+%s' % direction)


    def _tab_move(self, direction='forwards'):
        """Playback a tab or shift+tab for the given direction.

        @param direction: forwards or backwards.

        """
        assert direction in ['forwards', 'backwards']
        is_forwards = direction is 'forwards'
        filename = 'keyboard_tab' if is_forwards else 'keyboard_shift+tab'
        self._player.blocking_playback_of_default_file(
                input_type='keyboard', filename=filename)


    def _set_feature(self, feature, value):
        """Set given feature to given value using a11y API call.

        Presupposes self._extension (with accessibilityFeatures enabled).

        @param feature: string of accessibility feature to change.
        @param value: boolean of expected value.

        @raises: error.TestError if feature cannot be set.

        """
        value_str = 'true' if value else 'false'
        cmd = ('window.__result = null;\n'
               'chrome.accessibilityFeatures.%s.set({value: %s});\n'
               'chrome.accessibilityFeatures.%s.get({}, function(d) {'
               'window.__result = d[\'value\']; });' % (
                       feature, value_str, feature))
        self._extension.ExecuteJavaScript(cmd)

        poll_cmd = 'window.__result == %s;' % value_str
        utils.poll_for_condition(
                lambda: self._extension.EvaluateJavaScript(poll_cmd),
                exception = error.TestError(
                        'Timeout while trying to set %s to %s' %
                        (feature, value_str)))


    def _get_chromevox_state(self):
        """Return whether ChromeVox is enabled or not.

        Presupposes self._extension (with management enabled).

        @returns: value of management.get.enabled.

        @raises: error.TestError if state cannot be determined.

        """
        cmd = ('window.__enabled = null;\n'
               'chrome.management.get(\'%s\', function(r) {'
               'if (r) {window.__enabled = r[\'enabled\'];} '
               'else {window.__enabled = false;}});' % self._CHROMEVOX_ID)
        self._extension.ExecuteJavaScript(cmd)

        poll_cmd = 'window.__enabled != null;'
        utils.poll_for_condition(
                lambda: self._extension.EvaluateJavaScript(poll_cmd),
                exception=error.TestError(
                        'ChromeVox: management.get.enabled was not set!'))
        return self._extension.EvaluateJavaScript('window.__enabled')


    def _confirm_chromevox_state(self, value):
        """Fail test unless ChromeVox state is given value.

        Presupposes self._extension (with management enabled).

        @param value: True or False, whether ChromeVox should be enabled.

        @raises: error.TestFail if actual state doesn't match expected.

        """
        utils.poll_for_condition(
                lambda: self._get_chromevox_state() == value,
                exception=error.TestFail('ChromeVox: enabled state '
                                         'was not %s.' % value),
                timeout=self._CVOX_STATE_TIMEOUT)


    def _get_chromevox_indicator(self, tab):
        """Return whether the orange ChromeVox highlight is present or not.

        Looks for the orange highlight on the given tab.

        @returns: whether 'cvox_indicator_container' is found on the page

        """
        cmd = ('document.getElementsByClassName('
               '  "cvox_indicator_container").length > 0;')
        return tab.EvaluateJavaScript(cmd)


    def _confirm_chromevox_indicator(self, value):
        """Fail test unless indicator state is given value.

        Presupposes self._tab (the tab on which to check).

        @param value: True or False, whether ChromeVox indicator should show.

        @raises: error.TestFail if actual state doesn't match expected.

        """
        utils.poll_for_condition(
                lambda: self._get_chromevox_indicator(self._tab) == value,
                exception=error.TestFail('ChromeVox: "Indicator present" '
                                         'was not %s.' % value),
                timeout=self._CVOX_INDICATOR_TIMEOUT)


    def _get_extension_path(self):
        """Return the path to the default accessibility extension.

        @returns: string of path to default extension.

        """
        this_dir = os.path.dirname(__file__)
        return os.path.join(this_dir, 'a11y_ext')
