
from __future__ import absolute_import
from __future__ import division

import errno
import logging
import time
from . import stats
from vdsm import utils
from vdsm import metrics
from vdsm.common import hooks
from vdsm.common.define import Kbytes, Mbytes
from vdsm.config import config
from vdsm.virt import vmstatus

haClient = None
try:
    import ovirt_hosted_engine_ha.client.client as haClient
except ImportError:
    pass


def get_stats(cif, sample, multipath=False):
    hooks.before_get_stats()
    ret = {}

    first_sample, last_sample, _ = sample
    decStats = stats.produce(first_sample, last_sample)

    if cif.irs:
        decStats['storageDomains'] = cif.irs.repoStats()
        del decStats['storageDomains']['status']
        if multipath:
            decStats['multipathHealth'] = cif.irs.multipath_health()
            del decStats['multipathHealth']['status']
    else:
        decStats['storageDomains'] = {}

    for var in decStats:
        ret[var] = utils.convertToStr(decStats[var])

    avail, commit = _memUsageInfo(cif)
    ret['memAvailable'] = avail // Mbytes
    ret['memCommitted'] = commit // Mbytes
    ret['memFree'] = _memFree() // Mbytes
    ret['swapTotal'], ret['swapFree'] = _readSwapTotalFree()
    (ret['vmCount'], ret['vmActive'], ret['vmMigrating'],
     ret['incomingVmMigrations'], ret['outgoingVmMigrations']) = \
        _countVms(cif)
    (tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec,
        dummy, dummy, dummy) = time.gmtime(time.time())
    ret['dateTime'] = '%02d-%02d-%02dT%02d:%02d:%02d GMT' % (
        tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec)
    ret['momStatus'] = cif.mom.getStatus()
    ret.update(cif.mom.getKsmStats())
    ret['netConfigDirty'] = str(cif._netConfigDirty)
    ret['haStats'] = _getHaInfo()
    if ret['haStats']['configured']:
        ret['haScore'] = ret['haStats']['score']

    ret = hooks.after_get_stats(ret)
    return ret


def send_metrics(hoststats):
    prefix = "hosts"
    data = {}

    try:
        for dom in hoststats['storageDomains']:
            storage_prefix = prefix + '.storage.' + dom
            dom_info = hoststats['storageDomains'][dom]
            data[storage_prefix + '.delay'] = dom_info['delay']
            data[storage_prefix + '.last_check'] = dom_info['lastCheck']

        metrics.send(data)
    except KeyError:
        logging.exception('Host metrics collection failed')


def _readSwapTotalFree():
    meminfo = utils.readMemInfo()
    return meminfo['SwapTotal'] // 1024, meminfo['SwapFree'] // 1024


def _memUsageInfo(cif):
    """
    Return an approximation of available memory for new VMs.
    """
    committed = 0
    for v in cif.getVMs().values():
        committed += v.mem_size_mb() * Mbytes
    meminfo = utils.readMemInfo()
    freeOrCached = (meminfo['MemFree'] +
                    meminfo['Cached'] +
                    meminfo['Buffers'] +
                    meminfo['SReclaimable']) * Kbytes
    available = (
        freeOrCached + config.getint('vars', 'host_mem_reserve') * Mbytes
    )
    return available, committed


def _memFree():
    """
    Return the actual free mem on host.
    """
    meminfo = utils.readMemInfo()
    return (meminfo['MemFree'] +
            meminfo['Cached'] +
            meminfo['Buffers'] +
            meminfo['SReclaimable']) * Kbytes


def _countVms(cif):
    count = active = incoming = outgoing = 0
    for vmId, v in cif.getVMs().items():
        try:
            count += 1
            status = v.lastStatus
            if status == vmstatus.UP:
                active += 1
            elif status == vmstatus.MIGRATION_DESTINATION:
                incoming += 1
            elif status == vmstatus.MIGRATION_SOURCE:
                outgoing += 1
        except:
            logging.error(vmId + ': Lost connection to VM')
    return count, active, incoming + outgoing, incoming, outgoing


def _getHaInfo():
    """
    Return Hosted Engine HA information for this host.
    """
    i = {
        'configured': False,
        'active': False,
        'score': 0,
        'globalMaintenance': False,
        'localMaintenance': False,
    }
    if haClient:
        try:
            instance = haClient.HAClient()
            host_id = instance.get_local_host_id()

            if host_id:
                i['configured'] = True
            else:
                return i

            stats = instance.get_all_stats(timeout=5)
            if 0 in stats:
                i['globalMaintenance'] = stats[0].get(
                    haClient.HAClient.GlobalMdFlags.MAINTENANCE,
                    False)
            if host_id in stats:
                i['active'] = stats[host_id]['live-data']
                i['score'] = stats[host_id]['score']
                i['localMaintenance'] = stats[host_id]['maintenance']
        except IOError as ex:
            if ex.errno == errno.ENOENT:
                logging.error(
                    ("failed to retrieve Hosted Engine HA score '{0}'"
                        "Is the Hosted Engine setup finished?")
                    .format(str(ex))
                )
            else:
                logging.exception(
                    "failed to retrieve Hosted Engine HA score"
                )
        except Exception:
            logging.exception("failed to retrieve Hosted Engine HA info")
    return i
