#!/usr/bin/python3
# -*- coding: utf-8 -*-

import argparse
import os
import shlex

from spoc import repo_local
from spoc.config import VOLUMES_DIR
from spoc.container import Container, State
from spoc.image import Image

def listing(state):
    if state == 'all':
        containers = repo_local.get_containers().keys()
    elif state == 'running':
        containers = [c for c in repo_local.get_containers() if Container(c).get_state() == State.RUNNING]
    elif state == 'stopped':
        containers = [c for c in repo_local.get_containers() if Container(c).get_state() == State.STOPPED]
    for container in containers:
        print(container)

def modify_depend(container, depend):
    if depend.startswith('!'):
        try:
            container.depends.remove(depend[1:])
        except KeyError:
            pass
    else:
        # Add the dependency and remove duplicates
        container.depends.append(depend)
        container.depends = list(set(container.depends))

def modify_mount(container, mount):
    volume,mountpoint = mount.split(':', 1)
    if mountpoint:
        container.mounts[volume] = mountpoint
    else:
        try:
            del container.mounts[volume]
        except KeyError:
            pass

def modify_env(container, env):
    key,value = env.split('=', 1)
    if value:
        container.env[key] = value
    else:
        try:
            del container.env[key]
        except KeyError:
            pass

def modify_container(container, depends, mounts, envs, uid, gid, cmd, cwd, ready, halt, autostart):
    for depend in depends:
        modify_depend(container, depend)
    for mount in mounts:
        modify_mount(container, mount)
    for env in envs:
        modify_env(container, env)
    autostart = autostart == 'on'
    args = locals()
    for member in ('uid', 'gid', 'cmd', 'cwd', 'ready', 'halt', 'autostart'):
        value = args[member]
        if value:
            setattr(container, member, value)

def create(container_name, image_name, depends, mounts, env, uid, gid, cmd, cwd, ready, halt, autostart):
    # Create container based on image definition and extrea fields
    container = Container(container_name, False)
    container.set_definition(Image(image_name).get_definition())
    modify_container(container, depends, mounts, env, uid, gid, cmd, cwd, ready, halt, autostart)
    container.create()

def modify(container_name, depends, mounts, env, uid, gid, cmd, cwd, ready, halt, autostart):
    # Change configuration of an existing container
    container = Container(container_name)
    modify_container(container, depends, mounts, env, uid, gid, cmd, cwd, ready, halt, autostart)
    container.create()

def destroy(container_name):
    # Remove container and its directory
    Container(container_name, False).destroy()

def start(container_name):
    # Start the container using init values from its definition
    Container(container_name).start()

def stop(container_name):
    # Stop the container using halt signal from its definition
    Container(container_name).stop()

def status(container_name):
    # Prints current running status of the container
    print(Container(container_name).get_state())

def execute(container_name, command, uid, gid):
    # Execute a command in container's namespace
    Container(container_name).execute(command, uid, gid)

parser = argparse.ArgumentParser(description='SPOC container manager')
parser.set_defaults(action=None)
subparsers = parser.add_subparsers()

parser_list = subparsers.add_parser('list')
parser_list.set_defaults(action=listing)
parser_list.add_argument('type', choices=('all', 'running', 'stopped'), default='all', const='all', nargs='?')

parser_create = subparsers.add_parser('create')
parser_create.set_defaults(action=create)
parser_create.add_argument('-d', '--depends', action='append', default=[], help='Add another container as a start dependency')
parser_create.add_argument('-m', '--mount', action='append', default=[], help='Add mount to the container - format volume:mountpoint[:file]')
parser_create.add_argument('-e', '--env', action='append', default=[], help='Add environment variable for the container - format KEY=value')
parser_create.add_argument('-u', '--uid', help='Sets the container init UID')
parser_create.add_argument('-g', '--gid', help='Sets the container init GID')
parser_create.add_argument('-c', '--cmd', help='Sets the container init command')
parser_create.add_argument('-w', '--workdir', help='Sets the container init working directory')
parser_create.add_argument('-r', '--ready', help='Sets the container ready command')
parser_create.add_argument('-s', '--stopsig', help='Sets the signal to be sent to init on container shutdown')
parser_create.add_argument('-a', '--autostart', choices=('on', 'off'), help='Sets the container to be automatically started after the host boots up')
parser_create.add_argument('container')
parser_create.add_argument('image')

parser_modify = subparsers.add_parser('modify')
parser_modify.set_defaults(action=modify)
parser_modify.add_argument('-d', '--depends', action='append', default=[], help='Add another container as a start dependency - prepend the name with ! to remove the dependency')
parser_modify.add_argument('-m', '--mount', action='append', default=[], help='Add mount to the container - format volume:mountpoint - specify empty mountpoint to remove the mount')
parser_modify.add_argument('-e', '--env', action='append', default=[], help='Add environment variable for the container - format KEY=value - specify empty value to remove the env')
parser_modify.add_argument('-u', '--uid', help='Sets the container init UID')
parser_modify.add_argument('-g', '--gid', help='Sets the container init GID')
parser_modify.add_argument('-c', '--cmd', help='Sets the container init command')
parser_modify.add_argument('-w', '--workdir', help='Sets the container init working directory')
parser_modify.add_argument('-r', '--ready', help='Sets the container ready command')
parser_modify.add_argument('-s', '--stopsig', help='Sets the signal to be sent to init on container shutdown')
parser_modify.add_argument('-a', '--autostart', choices=('on', 'off'), help='Sets the container to be automatically started after the host boots up')
parser_modify.add_argument('container')

parser_destroy = subparsers.add_parser('destroy')
parser_destroy.set_defaults(action=destroy)
parser_destroy.add_argument('container')

parser_start = subparsers.add_parser('start')
parser_start.set_defaults(action=start)
parser_start.add_argument('container')

parser_stop = subparsers.add_parser('stop')
parser_stop.set_defaults(action=stop)
parser_stop.add_argument('container')

parser_status = subparsers.add_parser('status')
parser_status.set_defaults(action=status)
parser_status.add_argument('container')

parser_exec = subparsers.add_parser('exec')
parser_exec.set_defaults(action=execute)
parser_exec.add_argument('-u', '--uid', help='Sets the command UID')
parser_exec.add_argument('-g', '--gid', help='Sets the command GID')
parser_exec.add_argument('container')
parser_exec.add_argument('command', nargs=argparse.REMAINDER)

args = parser.parse_args()

if args.action is listing:
    listing(args.type)
elif args.action is create:
    create(args.container, args.image, args.depends, args.mount, args.env, args.uid, args.gid, args.cmd, args.workdir, args.ready, args.stopsig, args.autostart)
elif args.action is modify:
    modify(args.container, args.depends, args.mount, args.env, args.uid, args.gid, args.cmd, args.workdir, args.ready, args.stopsig, args.autostart)
elif args.action is destroy:
    destroy(args.container)
elif args.action is start:
    start(args.container)
elif args.action is stop:
    stop(args.container)
elif args.action is status:
    status(args.container)
elif args.action is execute:
    execute(args.container, args.command, args.uid, args.gid)
else:
    parser.print_usage()