import os
import logging
import sys
import shutil
import time
import platform
from pylib import shell

class VirtualBox(object):
    def __init__(self, vboxmanage=None):
        if vboxmanage:
            self.__vboxmanage = vboxmanage
        else:
            self.__vboxmanage = self.scan_vboxmanage()

    def scan_vboxmanage(self):
        path = shutil.which("VBoxManage")
        if path:
            return path

        if platform.system() == "Windows":
            default_paths = ["C:\Program Files\Oracle\VirtualBox","D:\Program Files\Oracle\VirtualBox"]
            for p in default_paths:
                path = os.path.join(p, "VBoxManage.exe")
                if os.path.exists(path):
                    return path

        raise Exception("can't find install path of VirtualBox")

    def __getoutput(self, cmd):
        command = self.__vboxmanage + " " + cmd
        return shell.getoutput(command, shell=True).strip().split(os.linesep)

    def __run_command(self, cmd):
        command = self.__vboxmanage + " " + cmd
        shell.run_command(command, shell=True)

    def get_vm_list(self):
        lines = self.__getoutput("list vms")
        vms = []
        for line in lines:
            if len(line) > 0:
                vms.append(line.split()[0][1:-1])
        return vms

    def __get_default_machine_folder(self):
        lines = self.__getoutput("list systemproperties")
        for line in lines:
            if line.startswith("Default machine folder"):
                return line.split(":")[-1].strip()
        raise Exception("get default machine folder failed")

    # running, poweroff, saved, paused
    def vmstate(self, vmname):
        lines = self.__getoutput("showvminfo {} --machinereadable|grep VMState=".format(vmname))
        return lines[0].split('VMState="')[-1][:-1]

    def stop(self, vmname):
        self.__run_command("controlvm {} poweroff".format(vmname))

    # disk size (G)
    def create(self, vmname, memory, disk_size, bridge_adapter, iso, force=False, disk_path=None):
        vms = self.get_vm_list()
        logging.debug("existing vms: " + str(vms))
        if vmname in vms:
            if force:
                self.remove(vmname, True)
            else:
                raise Exception("there is a VM with the same name, if you want to recreate it, please specify --force in the command line")

        if disk_path:
            vdi = "{0}/{1}.vdi".format(disk_path, vmname)
        else:
            vdi = "{0}/{1}.vdi".format(self.__get_default_machine_folder(), vmname)
        logging.debug(vdi)
        cmds = []
        self.__run_command("createvm --name {0} --ostype Debian_64 --register".format(vmname))
        self.__run_command("modifyvm {0} --memory {1}".format(vmname, memory))
        self.__run_command("modifyvm {0} --boot1 disk --boot2 dvd --boot3 net --boot4 none".format(vmname))

        if bridge_adapter:
            self.__run_command('modifyvm {0} --bridgeadapter1 "{1}"'.format(vmname, bridge_adapter))
            self.__run_command("modifyvm {0} --nic1 bridged".format(vmname))
        self.__run_command('createhd --filename "{0}" --size {1} --format VDI'.format(vdi, disk_size*1024))
        self.__run_command("storagectl {0} --name SATA_Controller --add sata --controller IntelAhci".format(vmname))
        self.__run_command('storageattach {0} --storagectl SATA_Controller --port 0 --device 0 --type hdd --medium "{1}"'.format(vmname, vdi))
        self.__run_command("storagectl {0} --name IDE_Controller --add ide --controller PIIX4".format(vmname))
        self.__run_command('storageattach {0} --storagectl IDE_Controller --port 1 --device 0 --type dvddrive --medium "{1}"'.format(vmname, iso))

    def start(self, vmname):
        self.__run_command("startvm " + vmname)

    def remove(self, vmname, force):
        if self.vmstate(vmname) == "running":
            self.stop(vmname)
        time.sleep(1)  #TODO: use better method to detect machine is unlocked
        self.__run_command("unregistervm {} --delete".format(vmname))

    def get_nic_list(self):
        nics = []
        lines = self.__getoutput("list bridgedifs|grep ^Name:")
        for line in lines:
            nics.append(line.split("Name:")[-1].strip())
        return nics