import time
import re
from cloudshell.cp.vcenter.commands.ip_result import IpReason, IpResult


class VMIPManager(object):
    INTERVAL = 5
    IP_V4_PATTERN = re.compile('^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$')

    def get_ip(self, vm, default_network, match_function, cancellation_context, timeout, logger):
        self._validate_vmware_tools_installed(logger, vm)
        ip = None
        reason = IpReason.Success
        if not timeout:
            ip = self._obtain_ip(vm, default_network, match_function, logger)
            if not ip:
                reason = IpReason.NotFound
        else:
            time_elapsed = 0
            interval = self.INTERVAL
            while time_elapsed < timeout and not ip:
                if cancellation_context.is_cancelled:
                    reason = IpReason.Cancelled
                    break
                ip = self._obtain_ip(vm, default_network, match_function, logger)
                if not ip:
                    time_elapsed += interval
                    time.sleep(interval)

            if time_elapsed >= timeout:
                reason = IpReason.Timeout

        return IpResult(ip, reason)

    @staticmethod
    def get_ip_match_function(ip_regex=None):

        if(not ip_regex):
            return  re.compile('.*').match

        try:
            return re.compile(ip_regex).match
        except Exception as e:
            raise ValueError('Invalid IP REGEX : {0} '.format(ip_regex))

    def _obtain_ip(self, vm, default_network, match_function, logger):
        ip = None
        ips = self._get_ip_addresses(vm, default_network)

        if ips:
            logger.debug('Filtering IP adresses to limit to IP V4 \'{0}\''.format(','.join(ips)))
            ips = self._select_ip_by_match(ips, self.IP_V4_PATTERN.match)
        if ips:
            logger.debug('Filtering IP adresses by custom IP Regex'.format(','.join(ips)))
            ips = self._select_ip_by_match(ips, match_function)

        # select the first on that found
        if ips:
            ip = ips[0]

        return ip

    @staticmethod
    def _get_ip_addresses(vm, default_network):
        ips = []
        if vm.guest.ipAddress:
            ips.append(vm.guest.ipAddress)
        for nic in vm.guest.net:
            if nic.network != default_network:
                for addr in nic.ipAddress:
                    if addr:
                        ips.append(addr)
        return ips

    @staticmethod
    def _select_ip_by_match(ips, match_function):
        return [ip for ip in ips if match_function(ip)]

    @staticmethod
    def _validate_vmware_tools_installed(logger, vm):
        if vm.guest.toolsStatus == 'toolsNotInstalled':
            msg = 'VMWare Tools status on virtual machine \'{0}\' are not installed'.format(vm.name)
            logger.warning(msg)
            raise ValueError(msg)
        return True