# Copyright (c) 2013 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 datetime
import random
import time

from autotest_lib.server import hosts
from autotest_lib.server import frontend
from autotest_lib.server import site_linux_system
from autotest_lib.server.cros import host_lock_manager
from autotest_lib.server.cros.chaos_ap_configurators import ap_batch_locker
from autotest_lib.server.cros.chaos_ap_configurators import ap_cartridge


class ChaosRunner(object):
    """Object to run a network_WiFi_ChaosXXX test."""


    def __init__(self, test, host, wifi_client, ap_spec):
        """Initializes and runs test.

        @param test: a string, test name.
        @param host: an Autotest host object, device under test.
        @param wifi_client: a WiFiClient object
        @param ap_spec: an APSpec object

        """
        self._test = test
        self._host = host
        self._wifi_client = wifi_client
        self._ap_spec = ap_spec
        # Log server and DUT times
        dt = datetime.datetime.now()
        logging.info('Server time: %s', dt.strftime('%a %b %d %H:%M:%S %Y'))
        logging.info('DUT time: %s', self._host.run('date').stdout.strip())


    @staticmethod
    def _allocate_packet_capturer(lock_manager, hostname):
        """Allocates a machine to capture packets.

        Locks the allocated machine if the machine was discovered via AFE
        to prevent tests stomping on each other.

        @param lock_manager HostLockManager object.
        @param hostname string optional hostname of a packet capture machine.

        """
        if hostname is not None:
            return hosts.SSHHost(hostname)

        afe = frontend.AFE(debug=True)
        potential_hosts = afe.get_hosts(multiple_labels=['packet_capture'])
        if not potential_hosts:
            raise error.TestError('No packet capture machines available.')

        # Shuffle hosts so that we don't lock the same packet capture host
        # every time.  This prevents errors where a fault might seem repeatable
        # because we lock the same packet capturer for each test run.
        random.shuffle(potential_hosts)
        for host in potential_hosts:
            if lock_manager.lock([host.hostname]):
                logging.info('Locked packet capture host %s.', host.hostname)
                return hosts.SSHHost(host.hostname + '.cros')
            else:
                logging.info('Unable to lock packet capture host %s.',
                             host.hostname)

        raise error.TestError('Could not allocate a packet tracer.')


    def _power_down_aps(self, aps):
         """Powers down a list of aps.

         @param aps: a list of APConfigurator objects.

         """
         cartridge = ap_cartridge.APCartridge()
         for ap in aps:
             ap.power_down_router()
             cartridge.push_configurator(ap)
         cartridge.run_configurators()


    def _configure_aps(self, aps):
        """Configures a given list of APs.

        @param aps: a list of APConfigurator objects.

        """
        cartridge = ap_cartridge.APCartridge()
        for ap in aps:
            # Update the unique id so the SSID is unique for each AP.
            self._ap_spec.unique_id = ap.get_router_short_name()
            ap.set_using_ap_spec(self._ap_spec)
            cartridge.push_configurator(ap)
        cartridge.run_configurators()


    def verify_bss_in_scan(self, bss):
        """Runs a scan on the DUT and verifies the SSID is being broadcasted.

        @param bss: the BSS to scan for

        @returns True is the SSID is found; false otherwise

        """
        scan_bss = '%s %s scan' % (self._wifi_client.command_iw,
                                   self._wifi_client.wifi_if)
        start_time = int(time.time())
        # Setting 300s as timeout
        logging.info('Waiting for the DUT to find BSS %s... ', bss)
        while (int(time.time()) - start_time) < 300:
           # If command failed: Device or resource busy (-16), run again.
           scan_result = self._wifi_client.host.run(scan_bss,
                                                    ignore_status=True)
           if 'busy' in str(scan_result):
               continue
           if bss in str(scan_result):
               logging.debug('Found bss %s in scan', bss)
               return True
           else:
               continue
        return False


    def run(self, job, batch_size=15, tries=10, capturer_hostname=None):
        """Executes Chaos test.

        @param job: an Autotest job object.
        @param batch_size: an integer, max number of APs to lock in one batch.
        @param tries: an integer, number of iterations to run per AP.
        @param capturer_hostname: a string or None, hostname or IP of capturer.

        """

        lock_manager = host_lock_manager.HostLockManager()
        with host_lock_manager.HostsLockedBy(lock_manager):
            capture_host = self._allocate_packet_capturer(
                    lock_manager, hostname=capturer_hostname)
            capturer = site_linux_system.LinuxSystem(capture_host, {},
                                                     'packet_capturer')
            batch_locker = ap_batch_locker.ApBatchLocker(lock_manager,
                                                         self._ap_spec)
            while batch_locker.has_more_aps():
                aps = batch_locker.get_ap_batch(batch_size=batch_size)
                if not aps:
                    logging.info('No more APs to test.')
                    break

                # Power down all of the APs because some can get grumpy
                # if they are configured several times and remain on.
                # User the cartridge to down group power downs and
                # configurations.
                self._power_down_aps(aps)
                self._configure_aps(aps)

                for ap in aps:
                    # http://crbug.com/306687
                    if ap.ssid == None:
                        logging.error('The SSID was not set for the AP:%s', ap)

                    if not ap.get_configuration_success():
                        # The AP was not configured correctly
                        job.run_test('network_WiFi_ChaosConfigFailure',
                                     ap=ap,
                                     tag=ap.ssid)
                        continue
                    if not self.verify_bss_in_scan(ap.get_bss()):
                        # The BSS of the AP was not found
                        job.run_test('network_WiFi_ChaosConfigFailure',
                                     ap=ap,
                                     missing_from_scan=True,
                                     tag=ap.ssid)
                        continue
                    # Refresh the unique_id for this AP.
                    self._ap_spec.unique_id = ap.get_router_short_name()
                    result = job.run_test(self._test,
                                 capturer=capturer,
                                 host=self._host,
                                 ap_spec=self._ap_spec,
                                 client=self._wifi_client,
                                 tries=tries,
                                 # Copy all logs from the system
                                 disabled_sysinfo=False,
                                 tag=ap.ssid)

                    logging.info('Test result: %d', result)

                    batch_locker.unlock_one_ap(ap.host_name)

                batch_locker.unlock_aps()
