#!/usr/bin/env python3
# ==============================================================================
#  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; either version 3 of the License, or
#  (at your option) any later version.
#
#  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, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
# ==============================================================================

# Filesystem
from pathlib import Path

# Logging
import logging

# System
from argparse import ArgumentParser

from subprocess import run
from subprocess import PIPE
from subprocess import Popen

from shlex import split as shlex_split

try:
    from xdg.DesktopEntry import DesktopEntry

except ImportError as error:
    from sys import exit as sys_exit

    sys_exit("Cannot import python3-xdg: %s" % str(error))

# ==============================================================================
#   Launcher
# ==============================================================================

def main():
    """ Main launcher
    """

    # Generate default arguments
    parser = ArgumentParser(
        description="A pretty launcher for Desktop file",
        epilog="Copyleft 2018 - Kawa-Team", conflict_handler="resolve")

    parser.add_argument("-v", "--version", action="version",
        version="run-desktop - Licence GPLv3", help="show the current version")

    parser_flag = parser.add_argument_group("flag arguments")
    parser_flag.add_argument("--disable-powersaving",
        action="store_true", help="disable powersaving during execution")

    parser.add_argument("DESKTOP", help="desktop file to launch")

    args = parser.parse_args()

    # ----------------------------------------
    #   Logging module
    # ----------------------------------------

    logging.basicConfig(format='%(message)s', level=logging.DEBUG)

    # ----------------------------------------
    #   Check desktop file
    # ----------------------------------------

    filepath = Path(args.DESKTOP).expanduser()

    if not filepath.exists():
        raise OSError(2, "Cannot found file %s" % filepath)

    # ----------------------------------------
    #   Parse desktop file
    # ----------------------------------------

    # Generate object from desktop file
    desktop = DesktopEntry(str(filepath))

    if desktop.getExec() is None or len(desktop.getExec()) == 0:
        raise ValueError(
            "Cannot found an Exec value in %s desktop file" % filepath.stem)

    # ----------------------------------------
    #   Read desktop file
    # ----------------------------------------

    logging.info(">>> Read %s metadata" % filepath.name)

    metadata = (
        ("Name", desktop.getName()),
        ("Path", desktop.getPath()),
        ("Command", desktop.getExec()))

    for key, value in metadata:
        if value is not None and len(value) > 0:
            logging.info("%s: %s" % (key, value))

    # ----------------------------------------
    #   Launch application
    # ----------------------------------------

    process_error = False

    process = None

    try:
        # Manage power-saving mode
        if args.disable_powersaving:
            logging.debug(">>> Block power-saving mode")

            run(shlex_split("xset -dpms"))

        logging.info(">>> Start %s" % desktop.getName())

        # Launch application
        process = Popen(shlex_split(desktop.getExec()), stdout=PIPE,
            start_new_session=True, cwd=Path(desktop.getPath()).expanduser())

        # Print application output in main stdout
        for line in iter(process.stdout.readline, bytes(str(), "UTF-8")):
            try:
                logging.info(line.decode("UTF-8")[:-1])

            except UnicodeDecodeError as error:
                logging.error(error)

        # Wait until application terminate
        process.wait()

        # Retrieve application return code
        process_error = process.returncode

    except KeyboardInterrupt:
        print() # Just to have a pretty output :D

        logging.warning(">>> Interrupt process")

        if process is not None:
            process.terminate()

    except PermissionError as error:
        logging.error(">>> Cannot execute binary: missing execution flag")

        process_error = True

    except Exception as error:
        logging.exception(">>> %s" % error)

        process_error = True

    # ----------------------------------------
    #   Close program
    # ----------------------------------------

    # Manage power-saving mode
    if args.disable_powersaving:
        logging.debug(">>> Restore power-saving mode")

        run(shlex_split("xset +dpms"))

    return process_error


if __name__ == "__main__":
    main()
