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

# Copyright (C) 2015 Canonical Ltd.
# Author: Christopher Townsend <christopher.townsend@canonical.com>

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import sys
import json
import lxc
import psutil
import shlex
import xdg.BaseDirectory as basedir

home_path = os.environ['HOME']

libertine_json_file_path = os.path.join(basedir.xdg_data_home, 'libertine', 'ContainersConfig.json')
libertine_container_path = basedir.save_cache_path('libertine-container')
libertine_userdata_path = os.path.join(basedir.xdg_data_home, 'libertine-container', 'user-data')

def get_container_type(container_id):
    container_type = ''

    with open(libertine_json_file_path) as fd:
        container_list = json.load(fd)
        fd.close()

    for container in container_list["containerList"]:
        if container["id"] == container_id:
            return container["type"]

    return ""

def get_container_path(container_id):
    return os.path.join(libertine_container_path, container_id, "rootfs")

def get_userdata_path(container_id):
    return os.path.join(libertine_userdata_path, container_id)

def set_dbus_session_socket_path():
    unique_id = os.environ['DISPLAY'].strip(':')
    user_id = os.getuid()

    dbus_session_socket_path = os.path.join('/', 'run', 'user', str(user_id), 'host_dbus_session' + unique_id)

    os.environ['DBUS_SESSION_BUS_ADDRESS'] = "unix:path=" + dbus_session_socket_path

    return dbus_session_socket_path

def launch_libertine_session_bridge():
    libertine_session_bridge_cmd = "libertine-session-bridge " + set_dbus_session_socket_path()

    args = shlex.split(libertine_session_bridge_cmd)
    return psutil.Popen(args)

def build_proot_command(container_id):
    proot_cmd = '/usr/bin/proot'
    if not os.path.isfile(proot_cmd) or not os.access(proot_cmd, os.X_OK):
        raise RuntimeError('executable proot not found')
    proot_cmd += " -R " + get_container_path(container_id)

    # Bind-mount the host's locale(s)
    proot_cmd += " -b /usr/lib/locale"

    # Bind-mount common XDG direcotries
    bind_mounts = " -b %s:%s" % (get_userdata_path(container_id), home_path)

    xdg_user_dirs = ['Documents', 'Music', 'Pictures', 'Videos']
    for user_dir in xdg_user_dirs:
        user_dir_path = os.path.join(home_path, user_dir)
        bind_mounts += " -b %s:%s" % (user_dir_path, user_dir_path)

    proot_cmd += bind_mounts
    return proot_cmd

def launch_lxc_application(container_id, app_exec_line):
    container = lxc.Container(container_id, libertine_container_path)

    if not container.running:
        if not container.start():
            print("Container failed to start")
            return
        if not container.wait("RUNNING", 10):
            print("Container failed to enter the RUNNING state")
            return

    if not container.get_ips(timeout=30):
        print("Not able to connect to the network.")
        return

    container.attach_wait(lxc.attach_run_command, app_exec_line)

def launch_chroot_application(container_id, app_exec_line):
    proot_cmd = build_proot_command(container_id)

    args = shlex.split(proot_cmd)
    args.extend(['compiz'])
    compiz = psutil.Popen(args)

    args = shlex.split(proot_cmd)
    args.extend(app_exec_line)
    psutil.Popen(args).wait()

    for child in compiz.children():
        child.terminate()

if __name__ == '__main__':
    container_id = sys.argv[1]
    app_exec_line = sys.argv[2:]
    container_type = get_container_type(container_id)

    session_bridge = launch_libertine_session_bridge()

    if container_type == "lxc":
        launch_lxc_application(container_id, app_exec_line)
    elif container_type == "chroot":
        launch_chroot_application(container_id, app_exec_line)

    session_bridge.terminate()
