#!/usr/bin/python3

import sys
import os
import subprocess
import shlex
import shutil

def usage():
    print("""
This is the Linux Mint "apt" command.

This commands acts as a wrapper for the APT package manager and many other useful tools such as apt-get, apt-cache, apt-mark, dpkg, aptitude...etc.

It is installed in /usr/local/bin/apt. To use the upstream apt command directly type /usr/bin/apt.

Usage: apt command [options]
       apt help command [options]

Commands:
  add-repository   - Add entries to apt sources.list
  autoclean        - Erase cache for packages no longer available
  autopurge        - Erase system-wide config files left by removed packages
  autoremove       - Remove dependency packages no longer required
  build            - Build binary or source packages from sources
  build-dep        - Configure build-dependencies for source packages
  changelog        - View a package's changelog
  check            - Verify there are no broken dependencies
  clean            - Erase downloaded archive files
  contains         - List packages containing a file
  content          - List files contained in and installed by a package(s)
  deb              - Install a local .deb package
  depends          - Show package dependency information
  dist-upgrade     - Fully upgrade the system by allowing other package changes
  download         - Download packages to the current working directory
  edit-sources     - Edit /etc/apt/sources.list with your preferred text editor
  dselect-upgrade  - Follow dselect selections
  full-upgrade     - Same as 'dist-upgrade'
  held             - List all held packages
  help             - Show help for a command
  hold             - Hold a package
  install          - Install and/or upgrade packages
  list             - List packages handled by the system (e.g., installed)
  policy           - Show policy settings
  purge            - Remove packages and their system-wide configuration files
  recommends       - List missing recommended packages for a particular package
  rdepends         - Show reverse dependency information for a package
  reinstall        - Reinstall packages or install if not yet installed
  remove           - Remove packages
  search           - Search for a package by name and/or expression
  show             - Display detailed information about a package
  showhold         - Same as 'held'
  showsrc          - Display source package records matching the given package
  source           - Download source archives
  sources          - Same as 'edit-sources'
  unhold           - Unhold a package
  update           - Download lists of new/upgradable packages
  upgrade          - Perform a safe upgrade
  version          - Show the installed version of a package
    """)

    sys.exit(1)

aliases = {
    "dist-upgrade": "full-upgrade",
    "sources": "edit-sources",
    "held": "showhold"
}

if any(arg == "--version" for arg in sys.argv[1:]):
    try:
        version = subprocess.check_output(["/usr/bin/apt", "--version"], text=True).splitlines()[0]
        print(f"{version} (Mint wrapper)")
    except Exception:
        print("apt (Mint wrapper) - version info unavailable")
    sys.exit(0)

if len(sys.argv) < 2:
    usage()

argcommand = sys.argv[1]
argoptions = sys.argv[2:]

for command in ["install", "remove", "update", "clean"]:
    if argcommand.startswith("-") and command in argoptions:
        while argcommand != command:
            temp = argoptions[0]
            for i in range(1, len(argoptions)):
                argoptions[i-1] = argoptions[i]
            argoptions[len(argoptions)-1] = argcommand
            argcommand = temp

command = ""

show_help = False
sort = False
highlight = False

if argcommand == "help":
    if len(sys.argv) < 3:
        usage()
    show_help = True
    argcommand = sys.argv[2]
    argoptions = sys.argv[3:]

if argcommand in aliases.keys():
    argcommand = aliases[argcommand]

if argcommand in ("autoremove", "list", "show", "install", "remove", "purge", "update", "upgrade", "full-upgrade", "edit-sources", "showsrc", "autopurge"):
    # apt
    command = ["/usr/bin/apt", argcommand] + argoptions
elif argcommand in ("clean", "dselect-upgrade", "build-dep", "check", "autoclean", "source", "moo"):
    # apt-get
    command = ["apt-get", argcommand] + argoptions
elif argcommand in ("reinstall", ):
    # aptitude
    command = ["aptitude", argcommand] + argoptions
elif argcommand in ("stats", "depends", "rdepends", "policy"):
    # apt-cache
    command = ["apt-cache", argcommand] + argoptions
elif argcommand in ("changelog", ):
    if os.path.exists("/usr/lib/python3/dist-packages/mintcommon/apt_changelog.py"):
        command = ["/usr/lib/python3/dist-packages/mintcommon/apt_changelog.py"] + argoptions
    else:
        command = ["aptitude", argcommand] + argoptions
elif argcommand in ("recommends", ):
    command = ["/usr/lib/linuxmint/mintsystem/mint-apt-recommends.py"] + argoptions
elif argcommand in ("showhold", "hold", "unhold"):
    # apt-mark
    command = ["apt-mark", argcommand] + argoptions
elif argcommand in ("markauto", "markmanual"):
    # apt-mark
    command = ["apt-mark", argcommand[4:]] + argoptions
elif argcommand == "contains":
    command = ["dpkg", "-S"] + argoptions
elif argcommand == "content":
    command = ["dpkg", "-L"] + argoptions
elif argcommand == "deb":
    command = ["dpkg", "-i"] + argoptions
elif argcommand == "build":
    command = ["dpkg-buildpackage"] + argoptions
elif argcommand == "version":
    command = ["dpkg-buildpackage"] + argoptions
    try:
        version = subprocess.check_output("dpkg-query -f '${Version}' -W %s 2>/dev/null" % shlex.quote(" ".join(argoptions)), shell=True).decode("UTF-8")
        print(version)
    except:
        pass
    sys.exit(0)
elif argcommand == "download":
    command = ["/usr/lib/linuxmint/mintsystem/mint-apt-download.py"] + argoptions
elif argcommand == "add-repository":
    command = ["add-apt-repository"] + argoptions
elif argcommand == "search":
    columns = 80
    if sys.stdin.isatty():
        columns, rows = shutil.get_terminal_size(fallback = (80, 24))
    command = ["aptitude", "-w", str(columns), argcommand] + argoptions
else:
    usage()
    sys.exit(1)

# Sudo prefix, unless simulating an applicable command
if os.getuid() != 0:
    if argcommand in ("autoremove", "install", "remove", "purge", "update", "upgrade", "full-upgrade", "edit-sources", "clean", "dselect-upgrade", "build-dep", "check", "autoclean", "reinstall", "deb", "hold", "unhold", "add-repository", "markauto", "markmanual", "autopurge"):
        # The above commands for which simulating is applicable
        simoptfound = False
        if argcommand in ("autoremove", "install", "remove", "purge", "upgrade", "full-upgrade", "clean", "dselect-upgrade", "build-dep", "check", "autoclean", "reinstall"):
            for simarg in ('-s', '--simulate', '--just-print', '--dry-run', '--recon', '--no-act'):
                if simarg in argoptions:
                    simoptfound = True

        if not simoptfound:
            command = ["sudo"] + command

# Color highlighting
if argcommand in ("content", "version", "policy", "depends", "rdepends", "search") and len(argoptions) >= 1:
    highlight = True

# Sorting
if argcommand in ("content", "contains"):
    sort = True

if show_help:
    print("\"apt " + argcommand + " " + " ".join(argoptions) + "\" is equivalent to \"" + " ".join(command) + "\"")
else:
    try:
        if sort and highlight:
            ps1 = subprocess.Popen(command, stdout=subprocess.PIPE)
            ps2 = subprocess.Popen("sort", stdin=ps1.stdout, stdout=subprocess.PIPE)
            ps3 = subprocess.Popen(["highlight-mint"] + argoptions, stdin=ps2.stdout)
            ps3.wait()
        elif sort:
            ps1 = subprocess.Popen(command, stdout=subprocess.PIPE)
            ps2 = subprocess.Popen("sort", stdin=ps1.stdout)
            ps2.wait()
        elif highlight:
            ps1 = subprocess.Popen(command, stdout=subprocess.PIPE)
            ps2 = subprocess.Popen(["highlight-mint"] + argoptions, stdin=ps1.stdout)
            ps2.wait()
        else:
            return_code = subprocess.call(command)
            sys.exit(return_code)
    except KeyboardInterrupt:
        pass
