# Copyright 2014 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 logging
import time
from collections import namedtuple
from contextlib import contextmanager

from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.cros.chameleon import chameleon

ChameleonPorts = namedtuple('ChameleonPorts', 'connected failed')


class ChameleonPortFinder(object):
    """
    Responsible for finding all ports connected to the chameleon board.

    It does not verify if these ports are connected to DUT.

    """

    def __init__(self, chameleon_board):
        """
        @param chameleon_board: a ChameleonBoard object representing the
                                Chameleon board whose ports we are interested
                                in finding.

        """
        self.chameleon_board = chameleon_board
        self.connected = None
        self.failed = None


    def find_all_ports(self):
        """
        @returns a named tuple ChameleonPorts() containing a list of connected
                 ports as the first element and failed ports as second element.

        """
        self.connected = self.chameleon_board.get_all_ports()
        self.failed = []

        return ChameleonPorts(self.connected, self.failed)


    def find_port(self, interface):
        """
        @param interface: string, the interface. e.g: HDMI, DP, VGA
        @returns a ChameleonPort object if port is found, else None.

        """
        connected_ports = self.find_all_ports().connected

        for port in connected_ports:
            if port.get_connector_type().lower() == interface.lower():
                return port

        return None


    def __str__(self):
        ports_to_str = lambda ports: ', '.join(
                '%s(%d)' % (p.get_connector_type(), p.get_connector_id())
                for p in ports)

        if self.connected is None:
            text = 'No port information. Did you run find_all_ports()?'
        elif self.connected == []:
            text = 'No port detected on the Chameleon board.'
        else:
            text = ('Detected %d connected port(s): %s. \t'
                    % (len(self.connected), ports_to_str(self.connected)))

        if self.failed:
            text += ('DUT failed to detect Chameleon ports: %s'
                     % ports_to_str(self.failed))

        return text


class ChameleonInputFinder(ChameleonPortFinder):
    """
    Responsible for finding all input ports connected to the chameleon board.

    """

    def find_all_ports(self):
        """
        @returns a named tuple ChameleonPorts() containing a list of connected
                 input ports as the first element and failed ports as second
                 element.

        """
        self.connected = self.chameleon_board.get_all_inputs()
        self.failed = []

        return ChameleonPorts(self.connected, self.failed)


class ChameleonOutputFinder(ChameleonPortFinder):
    """
    Responsible for finding all output ports connected to the chameleon board.

    """

    def find_all_ports(self):
        """
        @returns a named tuple ChameleonPorts() containing a list of connected
                 output ports as the first element and failed ports as the
                 second element.

        """
        self.connected = self.chameleon_board.get_all_outputs()
        self.failed = []

        return ChameleonPorts(self.connected, self.failed)


class ChameleonVideoInputFinder(ChameleonInputFinder):
    """
    Responsible for finding all video inputs connected to the chameleon board.

    It also verifies if these ports are connected to DUT.

    """

    REPLUG_DELAY_SEC = 1

    def __init__(self, chameleon_board, display_facade):
        """
        @param chameleon_board: a ChameleonBoard object representing the
                                Chameleon board whose ports we are interested
                                in finding.
        @param display_facade: a display facade object, to access the DUT
                               display functionality, either locally or
                               remotely.

        """
        super(ChameleonVideoInputFinder, self).__init__(chameleon_board)
        self.display_facade = display_facade
        self._TIMEOUT_VIDEO_STABLE_PROBE = 10


    def _yield_all_ports(self, failed_ports=None, raise_error=False):
        """
        Yields all connected video ports and ensures every of them plugged.

        @param failed_ports: A list to append the failed port or None.
        @param raise_error: True to raise TestFail if no connected video port.
        @yields every connected ChameleonVideoInput which is ensured plugged
                before yielding.

        @raises TestFail if raise_error is True and no connected video port.

        """
        yielded = False
        all_ports = super(ChameleonVideoInputFinder, self).find_all_ports()

        # unplug all ports
        for port in all_ports.connected:
            if port.has_video_support():
                chameleon.ChameleonVideoInput(port).unplug()
                self.display_facade.reset_connector_if_applicable(
                        port.get_connector_type())

        for port in all_ports.connected:
            # Skip the non-video port.
            if not port.has_video_support():
                continue

            video_port = chameleon.ChameleonVideoInput(port)
            # Plug the port to make it visible.
            video_port.plug()
            try:
                # DUT takes some time to respond. Wait until the video signal
                # to stabilize and wait for the connector change.
                video_stable = video_port.wait_video_input_stable(
                        self._TIMEOUT_VIDEO_STABLE_PROBE)
                output = utils.wait_for_value_changed(
                        self.display_facade.get_external_connector_name,
                        old_value=False)

                if not output:
                    logging.warn('Maybe flaky that no display detected. Retry.')
                    video_port.unplug()
                    time.sleep(self.REPLUG_DELAY_SEC)
                    video_port.plug()
                    video_stable = video_port.wait_video_input_stable(
                            self._TIMEOUT_VIDEO_STABLE_PROBE)
                    output = utils.wait_for_value_changed(
                            self.display_facade.get_external_connector_name,
                            old_value=False)

                logging.info('CrOS detected external connector: %r', output)

                if output:
                    yield video_port
                    yielded = True
                else:
                    if failed_ports is not None:
                       failed_ports.append(video_port)
                    logging.error('CrOS failed to see any external display')
                    if not video_stable:
                        logging.warn('Chameleon timed out waiting CrOS video')
            finally:
                # Unplug the port not to interfere with other tests.
                video_port.unplug()

        if raise_error and not yielded:
            raise error.TestFail('No connected video port found between CrOS '
                                 'and Chameleon.')


    def iterate_all_ports(self):
        """
        Iterates all connected video ports and ensures every of them plugged.

        It is used via a for statement, like the following:

            finder = ChameleonVideoInputFinder(chameleon_board, display_facade)
            for chameleon_port in finder.iterate_all_ports()
                # chameleon_port is automatically plugged before this line.
                do_some_test_on(chameleon_port)
                # chameleon_port is automatically unplugged after this line.

        @yields every connected ChameleonVideoInput which is ensured plugged
                before yeilding.

        @raises TestFail if no connected video port.

        """
        return self._yield_all_ports(raise_error=True)


    @contextmanager
    def use_first_port(self):
        """
        Use the first connected video port and ensures it plugged.

        It is used via a with statement, like the following:

            finder = ChameleonVideoInputFinder(chameleon_board, display_facade)
            with finder.use_first_port() as chameleon_port:
                # chameleon_port is automatically plugged before this line.
                do_some_test_on(chameleon_port)
                # chameleon_port is automatically unplugged after this line.

        @yields the first connected ChameleonVideoInput which is ensured plugged
                before yeilding.

        @raises TestFail if no connected video port.

        """
        for port in self._yield_all_ports(raise_error=True):
            yield port
            break


    def find_all_ports(self):
        """
        @returns a named tuple ChameleonPorts() containing a list of connected
                 video inputs as the first element and failed ports as second
                 element.

        """
        dut_failed_ports = []
        connected_ports = list(self._yield_all_ports(dut_failed_ports))
        self.connected = connected_ports
        self.failed = dut_failed_ports

        return ChameleonPorts(connected_ports, dut_failed_ports)


class ChameleonAudioInputFinder(ChameleonInputFinder):
    """
    Responsible for finding all audio inputs connected to the chameleon board.

    It does not verify if these ports are connected to DUT.

    """

    def find_all_ports(self):
        """
        @returns a named tuple ChameleonPorts() containing a list of connected
                 audio inputs as the first element and failed ports as second
                 element.

        """
        all_ports = super(ChameleonAudioInputFinder, self).find_all_ports()
        self.connected = [chameleon.ChameleonAudioInput(port)
                          for port in all_ports.connected
                          if port.has_audio_support()]
        self.failed = []

        return ChameleonPorts(self.connected, self.failed)


class ChameleonAudioOutputFinder(ChameleonOutputFinder):
    """
    Responsible for finding all audio outputs connected to the chameleon board.

    It does not verify if these ports are connected to DUT.

    """

    def find_all_ports(self):
        """
        @returns a named tuple ChameleonPorts() containing a list of connected
                 audio outputs as the first element and failed ports as second
                 element.

        """
        all_ports = super(ChameleonAudioOutputFinder, self).find_all_ports()
        self.connected = [chameleon.ChameleonAudioOutput(port)
                          for port in all_ports.connected
                          if port.has_audio_support()]
        self.failed = []

        return ChameleonPorts(self.connected, self.failed)
