# -*- coding: utf-8 -*-

import os
import re
import psutil
from subprocess import Popen, PIPE, STDOUT
from multiprocessing import cpu_count
from platform import platform, machine, system
from socket import gethostbyaddr, gethostname
from jobs import JobManager
from lvm import LVM
from drbd import DRBDPool


class Host(object):
    '''
    Root class for all physical or virtual machines that CloudControl Node may
    run on, or manage. It is not intended for direct usage by NodeHandler.
    '''


class LocalHost(Host):
    '''
    Regular host with no hypervisor support, all methods defined here are
    expected to provide information to the NodeHandler.
    '''
    
    ARCH = {
        'i386' : 'x86',
        'i486' : 'x86',
        'i586' : 'x86',
        'i686' : 'x86',
        'x86_64' : 'x64',
    }
    
    def __init__(self):
        '''
        '''
        super(LocalHost, self).__init__()
        self.jobmgr = JobManager()
        self.drbdpool = DRBDPool()
        self.lvm = LVM()
    
    def scheduler_run(self):
        '''
        '''
        pass
    
    def get_hw_serial(self):
        '''
        '''
        serial = None
        data = open('/sys/class/dmi/id/product_serial').read().strip()
        if data:
            serial = data
        return serial
    
    def get_hw_vendor(self):
        '''
        '''
        vendor = None
        data = open('/sys/class/dmi/id/sys_vendor').read().strip()
        if data:
            vendor = data
        return vendor
    
    def get_hw_product(self):
        '''
        '''
        product = None
        data = open('/sys/class/dmi/id/product_name').read().strip()
        if data:
            product = data
        return product
    
    def get_hw_bios(self):
        '''
        '''
        bios = ''
        bios_ver = open('/sys/class/dmi/id/bios_version').read().strip()
        bios_date = open('/sys/class/dmi/id/bios_date').read().strip()
        if bios_ver:
            bios += bios_ver
        if bios_date:
            bios += ' (%s)' % bios_date
        if not bios:
            bios = None
        return bios
    
    def get_chassis_asset(self):
        '''
        '''
        asset = None
        data = open('/sys/class/dmi/id/chassis_asset_tag').read().strip()
        if data:
            asset = data
        return asset
    
    def get_chassis_serial(self):
        '''
        '''
        serial = None
        data = open('/sys/class/dmi/id/chassis_serial').read().strip()
        if data:
            serial = data
        return serial
    
    def get_name(self):
        '''
        '''
        result = None
        hostname = gethostname()
        fqdn = gethostbyaddr(hostname)[0]
        result = fqdn if fqdn else hostname
        return result
    
    def get_uname(self):
        '''
        '''
        uname = None
        data = ' '.join(os.uname())
        if data:
            uname = data
        return uname
    
    def get_platform(self):
        '''
        '''
        result = None
        try:
            p = platform()
            if p:
                result = p
        except:
            pass
        return result
    
    def get_system(self):
        '''
        '''
        result = None
        try:
            p = system()
            if p:
                result = p.lower()
        except:
            pass
        return result
    
    def get_uptime(self):
        '''
        '''
        uptime = None
        try:
            data = open("/proc/uptime").read().split()
            if data:
                uptime = int(float(data[0]))
        except:
            pass
        return uptime
    
    def get_loadavg(self):
        '''
        '''
        load = None
        try:
            data = ' '.join('%.2f' % load for load in os.getloadavg())
            if data:
                load = data
        except:
            pass
        return load
    
    def get_arch(self):
        '''
        '''
        arch = None
        try:
            a = machine()
            if a in self.ARCH:
                arch = self.ARCH[a]
        except:
            pass
        return arch
    
    def get_cpu(self):
        '''
        '''
        cpucount = None
        try:
            data = cpu_count()
            if data:
                cpucount = data
        except:
            pass
        return cpucount
    
    def get_cpu_usage(self):
        '''
        '''
        usage = None
        try:
            data = '%.1f' % psutil.cpu_percent()
            if data:
                usage = data
        except:
            pass
        return usage
    
    def get_mem(self):
        '''
        '''
        mem = None
        try:
            data = psutil.avail_phymem() + psutil.used_phymem()
            if data:
                mem = data
        except:
            pass
        return mem
    
    def get_mem_free(self):
        '''
        '''
        free = None
        try:
            data = psutil.avail_phymem()
            if data:
                free = data
        except:
            pass
        return free
    
    def get_mem_used(self):
        '''
        '''
        used = None
        try:
            data = psutil.used_phymem()
            if data:
                used = data
        except:
            pass
        return used
    
    def get_disks(self):
        '''
        '''
        disks = {}
        try:
            re_pattern = re.compile(r'([sh]d[a-z]+)')
            found = [bd for bd in os.listdir('/sys/block/')
                                                        if re_pattern.match(bd)]
            for disk in found:
                fullname = os.path.join('/sys/block', disk, 'size')
                size = int(open(fullname).read())
                if size > 0:
                    disks[disk] = size * 512
        except:
            pass
        return disks
    
    def power_shutdown(self):
        '''
        '''
        return self.execute('/sbin/shutdown -h -P 0')
    
    def power_off(self):
        '''
        '''
        return self.execute('/sbin/shutdown -h -P -n 0')
    
    def power_reboot(self):
        '''
        '''
        return self.execute('/sbin/shutdown -r -f 0')
    
    def power_force_reboot(self):
        '''
        '''
        return self.execute('/sbin/shutdown -r -n 0')
    
    def execute(self, command):
        '''
        '''
        output = None
        try:
            #FIXME: stop using shell=true and parse arguments with shlex.split()
            data = Popen(command,
                         shell=True,
                         bufsize=-1,
                         stdin=PIPE,
                         stdout=PIPE,
                         stderr=STDOUT).communicate()[0]
            if data:
                output = data
        except:
            pass
        return output


class Hypervisor(LocalHost):
    '''
    '''
    
    def __init__(self):
        '''
        '''
        super(Hypervisor, self).__init__()
    
    def storage(self):
        '''
        '''
        raise NotImplementedError
    
    def vm_list(self):
        '''
        '''
        raise NotImplementedError
    
    def vm_list_running(self):
        '''
        '''
        raise NotImplementedError

    def vm_list_stopped(self):
        '''
        '''
        raise NotImplementedError
        
    def vm_list_paused(self):
        '''
        '''
        raise NotImplementedError
    
    def vm_get(self, name):
        '''
        '''
        raise NotImplementedError


class VM(Host):
    '''
    '''


class Storage(object):
    '''
    '''


class StoragePool(object):
    '''
    '''


class StorageVolume(object):
    '''
    '''