#!/usr/bin/python3
import argparse
import os
import subprocess
import sys

import apt

# Virtual package mapping
virtual_mapping = {'awk':               'gawk', 
                   'perlapi-5.18.1':    'perl-base',
                   'perlapi-5.18.2':    'perl-base',
                   'upstart-job':       'upstart',
                   'python:any':        'python2.7',
                   'python3:any':       'python3.4',
                   'whiptail-provider': 'whiptail',
                   'libselinux-dev':    'libselinux1-dev',
                   'systemd':           'systemd-shim'}

def main():
    
    parser = argparse.ArgumentParser(description='Process some integers.')
    parser.add_argument('-v', '--verbose', action='store_true',
                        help='write additional information to stderr')
    parser.add_argument('-d', '--download', action='store_true',
                        help='do not print package list, instead download '
                             'packages to the specified directory')
    parser.add_argument('--directory', type=str, 
                        help='download directory')
    parser.add_argument('input_package_files', action='store',
                        help='a comma separated list of files containing '
                             'package names, one per line')
    args = parser.parse_args()
    
    #~ print(args)
    #~ return 0
    
    # Input packages
    in_packages = []
    
    # Parse input package files
    for filename in args.input_package_files.split(','):
        with open(filename) as in_file:
            for line in in_file:
                line = line.strip()
                if line:
                    in_packages.append(line)
    
    # Open APT cache
    cache = apt.Cache(memonly=True)
    cache.open()
    
    # Create a set to hold the names of all packages and their dependencies
    packages = set()

    while True:
        try:
            # Grab next package 
            pkg_name = in_packages.pop()
            if args.verbose:    
                sys.stderr.write('Package: {:s}\n'.format(pkg_name))
                sys.stderr.flush()
      
            # Check if the package is in the cache, if not check if it is in
            # our list of known virtual packages
            if pkg_name not in cache:
                if pkg_name in virtual_mapping:
                    pkg_name = virtual_mapping[pkg_name]
                else:
                    sys.stderr.write('ERROR: unkown package "{:s}"; if this is '
                                     'a virtual package please add it to the '
                                     'virtual package mapping\n'.format(pkg_name))
                    continue
      
            # Add this package (with version) to the list of packages
            packages.add(pkg_name)

            # Get package dependencies
            for pdep in cache[pkg_name].versions[0].dependencies:
                dep_name = pdep[0].name
                if args.verbose:
                    sys.stderr.write('\tDependency: {:s}\n'.format(dep_name))
                    sys.stderr.flush()
                if dep_name not in packages:
                    if dep_name in virtual_mapping:
                        dep_name = virtual_mapping[dep_name]
                    packages.add(dep_name)
                    in_packages.insert(0, dep_name)
        except IndexError:
            break

    if not args.download:
        # Print out the gathered package names
        for package in sorted(packages):
            print(package)
    else:
        # Download packages
        if args.directory is not None:
            if not os.path.exists(args.directory):
                # Ask the user if they'd like to create the directory
                answer = input('The path "{:s}" does not exist, would you '
                               'like to create it? (Y/n) '.format(args.directory))
                if answer.lower().strip() not in ['y', 'yes']:
                    print('Directory not created, exiting')
                    return 0
                
                # Try to create the directory
                try:
                    os.makedirs(args.directory)
                except OSError as e:
                    if e.errno != errno.EEXIST:
                        raise e
                    print('ERROR: unable to create directory, exiting')
                    return -1
        else:
            args.directory = os.getcwd()
    
        # Download all of the packages
        package_list = ' '.join(sorted(packages))
        cmd = 'cd {:s}; apt-get download {:s}'
        cmd = cmd.format(args.directory, package_list)
        subprocess.call(cmd, shell=True)
            
    return 0
    
if __name__ == '__main__':
    sys.exit(main())
