#!/usr/bin/env python
# Copyright (C) 2014-2015 Jurriaan Bremer.
# This file is part of VMCloak - http://www.vmcloak.org/.
# See the file 'docs/LICENSE.txt' for copying permission.

import argparse
import logging

import vmcloak.dependencies

from vmcloak.agent import Agent
from vmcloak.exceptions import DependencyError
from vmcloak.misc import wait_for_host
from vmcloak.repository import Session, Image
from vmcloak.vm import VirtualBox
from vmcloak.winxp import WindowsXP
from vmcloak.win7 import Windows7

logging.basicConfig()
log = logging.getLogger("vmcloak-install")

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("name", type=str, help="Name of the instance.")
    parser.add_argument("dependencies", type=str, nargs="*", help="Dependencies to install.")
    parser.add_argument("--vm-visible", action="store_true", help="Start the Virtual Machine in GUI mode.")
    args = parser.parse_args()

    session = Session()

    image = session.query(Image).filter_by(name=args.name).first()
    if not image:
        log.error("Image not found: %s", args.name)
        exit(1)

    if image.mode != "normal":
        log.error("You can't install dependencies in this image as you have "
                  "already made snapshots with it!")
        log.error("Please vmcloak-clone it and update the clone.")
        exit(1)

    m = VirtualBox(name=args.name)

    if image.osversion == "winxp":
        h = WindowsXP()
        ramsize = 1024
    elif image.osversion == "win7" or image.osversion == "win7x64":
        h = Windows7()
        ramsize = 2048

    m.create_vm()
    m.os_type(image.osversion)
    m.cpus(image.cpus)
    m.mouse("usbtablet")
    m.ramsize(ramsize)
    m.attach_hd(image.path, multi=False)
    # Ensure the slot is at least allocated for by an empty drive.
    m.detach_iso()
    m.hostonly(nictype=h.nictype, adapter=image.adapter)
    m.start_vm(visible=args.vm_visible)
    wait_for_host(image.ipaddr, image.port)

    a = Agent(image.ipaddr, image.port)
    a.ping()

    settings = {}
    dependencies = []

    # First we fetch the configuration settings off of the arguments.
    for dependency in args.dependencies:
        if "." in dependency and "=" in dependency:
            key, value = dependency.split("=", 1)
            settings[key.strip()] = value.strip()
        elif ":" in dependency:
            dependency, version = dependency.split(":", 1)
            dependencies.append((dependency, version))
        else:
            dependencies.append((dependency, None))

    for dependency, version in dependencies:
        if dependency not in vmcloak.dependencies.names:
            log.error("Unknown dependency %s..", dependency)
            break

        if version:
            log.info("Installing dependency %s %s..", dependency, version)
        else:
            log.info("Installing dependency %s..", dependency)

        try:
            d = vmcloak.dependencies.names[dependency]
            d(h, m, a, image, version, settings).run()
        except DependencyError:
            log.error("The dependency %s returned an error..", dependency)
            break

    a.shutdown()
    m.wait_for_state(shutdown=True)

    m.remove_hd()
    m.compact_hd(image.path)
    m.delete_vm()

if __name__ == "__main__":
    main()
