#!/usr/bin/env python
import lxml.etree as ET

# VM Instance class


class VMInstance:
    name = None
    arch = None
    vm_type = None
    os_boot = None
    vcpu = None
    cpu_share = None
    memory_max = None
    network_list = list()
    disk_list = list()
    graphics = dict
    context = dict
    raw_data = None

    def __init__(self,
                 name,
                 vcpu,
                 memory_max,
                 cpu_share="100",
                 arch="x86_64",
                 os_boot="hd",
                 vm_type="kvm",
                 network_list=None,
                 disk_list=None,
                 context=None,
                 graphics=None,
                 acpi=True,
                 raw_data=None):
        '''Default Virtual Machine constructor
        name    - unique name for the instance
        vcpu    - nubmer of processors
        memory_max  - maximum virtual memory (actual memory maybe add late)
        cpu_share   - KVM process priority (0-100)
        arch        - libvirt arch parameter default x86_64
        os_boot     - boot device default hd
        vm_type     - hypervisor type default kvm
        network_list    - VMNetwork list
        disk_list   - VMDIsk list
        context  -   Key-Value pars (not used)
        graphics    - Dict that keys are: type, listen, port, passwd
        acpi        - True/False to enable acpi
        '''
        self.name = name
        self.vcpu = vcpu
        self.cpu_share = cpu_share
        self.memory_max = memory_max
        self.arch = arch
        self.os_boot = os_boot
        self.vm_type = vm_type
        self.network_list = network_list
        self.disk_list = disk_list
        self.conext = context
        self.graphics = graphics
        self.acpi = acpi
        self.raw_data = raw_data

    def build_xml(self):
        '''Return the root Element Tree object
        '''
        ET.register_namespace(
            'qemu', 'http://libvirt.org/schemas/domain/qemu/1.0')
        xml_top = ET.Element(
            'domain',
            attrib={
                'type': self.vm_type
            })
        # Basic virtual machine paramaters
        ET.SubElement(xml_top, 'name').text = self.name
        ET.SubElement(xml_top, 'vcpu').text = self.vcpu
        ET.SubElement(xml_top, 'memory').text = self.memory_max
        # Cpu tune
        cputune = ET.SubElement(xml_top, 'cputune')
        ET.SubElement(cputune, 'shares').text = self.cpu_share
        # Os specific options
        os = ET.SubElement(xml_top, 'os')
        ET.SubElement(os, 'type', attrib={'arch': self.arch}).text = "hvm"
        ET.SubElement(os, 'boot', attrib={'dev': self.os_boot})
        # Devices
        devices = ET.SubElement(xml_top, 'devices')
        ET.SubElement(devices, 'emulator').text = '/usr/bin/kvm'
        for disk in self.disk_list:
            devices.append(disk.build_xml())
        for network in self.network_list:
            devices.append(network.build_xml())
        # Console/graphics section
        if self.graphics is not None:
            ET.SubElement(devices,
                          'graphics',
                          attrib={
                              'type': self.graphics['type'],
                              'listen': self.graphics['listen'],
                              'port': self.graphics['port'],
                              'passwd': self.graphics['passwd'],
                          })
        # Features (TODO: features as list)
        features = ET.SubElement(xml_top, 'features')
        if self.acpi:
            ET.SubElement(features, 'acpi')
        # Building raw data into xml
        if self.raw_data is not None:
            xml_top.append(ET.fromstring(self.raw_data))
        return xml_top

    def dump_xml(self):
        return ET.tostring(self.build_xml(),
                           encoding='utf8',
                           method='xml',
                           pretty_print=True)


class VMDisk:

    '''Virtual MAchine disk representing class
    '''
    name = None
    source = None
    disk_type = None
    disk_device = None
    driver_name = None
    driver_type = None
    driver_cache = None
    target_device = None

    def __init__(self,
                 name,
                 source,
                 disk_type="file",
                 disk_device="disk",
                 driver_name="qemu",
                 driver_type="qcow2",
                 driver_cache="default",
                 target_device="vda"):
        self.name = name
        self.source = source
        self.disk_type = disk_type
        self.disk_device = disk_device
        self.driver_name = driver_name
        self.driver_type = driver_type
        self.driver_cache = driver_cache
        self.target_device = target_device

    def build_xml(self):
        xml_top = ET.Element('disk',
                             attrib={'type': self.disk_type,
                                     'device': self.disk_device})
        ET.SubElement(xml_top, 'source',
                      attrib={self.disk_type: self.source})
        ET.SubElement(xml_top, 'target',
                      attrib={'dev': self.target_device})
        ET.SubElement(xml_top, 'driver',
                      attrib={
                          'name': self.driver_name,
                          'type': self.driver_type,
                          'cache': self.driver_cache})
        return xml_top

    def dump_xml(self):
        return ET.tostring(self.build_xml(),
                           encoding='utf8',
                           method='xml',
                           pretty_print=True)


class VMNetwork:

    ''' Virtual Machine network representing class
    name            -- network device name
    bridge          -- bridg for the port
    mac             -- the MAC address of the quest interface
    ipv4            -- the IPv4 address of virtual machine (Flow control)
    ipv6            -- the IPv6 address of virtual machine (Flow controlo)
    vlan            -- Port VLAN configuration
    network_type    -- need to be "ethernet" by default
    model           -- available models in libvirt
    QoS             -- CIRCLE QoS class?
    comment         -- Any comment
    managed         -- Apply managed flow rules for spoofing prevent
    script          -- Executable network script /bin/true by default
    '''
    # Class attributes
    name = None
    bridge = None
    network_type = None
    mac = None
    model = None
    QoS = None
    script_exec = '/bin/true'
    comment = None
    vlan = 0
    ipv4 = None
    ipv6 = None
    managed = False

    def __init__(self,
                 name,
                 bridge,
                 mac,
                 ipv4=None,
                 ipv6=None,
                 network_type='ethernet',
                 model='virtio',
                 QoS=None,
                 vlan=0,
                 managed=False):
        self.name = name
        self.bridge = bridge
        self.network_type = network_type
        self.mac = mac
        self.ipv4 = ipv4
        self.ipv6 = ipv6
        self.model = model
        self.QoS = QoS
        self.vlan = vlan
        self.managed = managed

    # XML dump
    def build_xml(self):
        xml_top = ET.Element('interface', attrib={'type': self.network_type})
        ET.SubElement(xml_top, 'target', attrib={'dev': self.name})
        ET.SubElement(xml_top, 'mac', attrib={'address': self.mac})
        ET.SubElement(xml_top, 'model', attrib={'type': self.model})
        ET.SubElement(xml_top, 'script', attrib={'path': self.script_exec})
        ET.SubElement(xml_top, 'rom', attrib={'bar': 'off'})
        return xml_top

    def dump_xml(self):
        return ET.tostring(self.build_xml(), encoding='utf8',
                           method='xml', pretty_print=True)