#!/usr/bin/env python
from __future__ import (unicode_literals, absolute_import,
                        print_function, division)
import argparse
import sys
import json
import re
import base64
import calendar
import csv
import datetime
import hashlib
import glob
import itertools
import json
import math
import os
import random
import re
import shutil
import tempfile
from collections import Counter
from collections import OrderedDict
from collections import defaultdict
from itertools import groupby
from uuid import uuid4

import rlcompleter


def lazy_imports(*args):
    query = ' '.join([x for x in args if x])
    regex = re.compile("([a-zA-Z_][a-zA-Z0-9_]*)\.")
    matches = regex.findall(query)
    for module_name in matches:
        try:
            module = __import__(module_name)
            globals()[module_name] = module
        except ImportError as e:
            pass

    if 'Counter' in query: global Counter; from collections import Counter
    if 'OrderedDict' in query: global OrderedDict; from collections import OrderedDict
    if 'defaultdict' in query: global defaultdict; from collections import defaultdict
    if 'groupby' in query: global groupby; from itertools import groupby


def complete_all(prefix, completion_args):
    lazy_imports(prefix, completion_args['c_arg'])
    if completion_args:
        if completion_args['x_arg']:
            x = str()
        if completion_args['l_arg']:
            l = list()
        if completion_args['c_arg']:
            exec(completion_args['c_arg'].strip('"\'').replace("`", "'"))
    context = locals()
    context.update(globals())
    completer = rlcompleter.Completer(context)
    idx = 0
    options_set = set()
    while completer.complete(prefix, idx):
        options_set.add(completer.complete(prefix, idx))
        idx += 1

    module_completion, module_list = get_completerlib()
    options = module_completion("import " + prefix) or []
    if options:
        options = [x.rstrip(' ') for x in options if x.startswith(prefix)]

    return options + list(options_set)


def parse_string(input):
    options = []
    current_full = input[-1].lstrip('"\'')
    current_prefix = current_full.split(' ')[-1]
    prior = input[:-1]
    completion_args = defaultdict(lambda: None)
    if input[-1].startswith('--'):
        options = ['--si', '--so', '--ji', '--jo', '--i']
    elif input[-1].startswith('-'):
        options = ['-h', '-x', '-fx', '-l', '-c', '-C']
    elif len(prior) > 0 and prior[-1] == '-c':
        if 'import'.startswith(current_full):
            options = ["'import"]
        elif current_full.startswith('import ') or current_full.startswith('from '):
            module_completion, module_list = get_completerlib()
            options = module_completion(current_full) or []
            if options:
                options = [x.rstrip(' ') for x in options if x.startswith(current_prefix)]
        else:
            options = complete_all(current_prefix, completion_args)
            if current_prefix.endswith('.'):
                options = [x for x in options if '._' not in x]
    else:
        if current_full == '':
            options = ['sys', 'json', 're', 'csv', 'datetime', 'hashlib', 'itertools', 'math', 'os', 'random', 'shutil'] 
            if '-x' in input[:-1] or '-fx' in input[:-1]:
                options += 'x'
            if '-l' in input[:-1]:
                options += 'l'
        else:
            if '-x' in prior or '-fx' in prior:
                completion_args['x_arg'] = True
            if '-l' in prior:
                completion_args['l_arg'] = True
            if '-c' in prior:
                c_index = prior.index('-c')
                if (c_index + 1) < len(prior):
                    completion_args['c_arg'] = prior[c_index + 1]
            options = complete_all(current_prefix, completion_args)
            if current_prefix.endswith('.'):
                options = [x for x in options if '._' not in x]
    return options


def get_completerlib():
    """Implementations for various useful completers.

    These are all loaded by default by IPython.
    """
    #-----------------------------------------------------------------------------
    #  Copyright (C) 2010-2011 The IPython Development Team.
    #
    #  Distributed under the terms of the BSD License.
    #
    #  The full license is in the file COPYING.txt, distributed with this software.
    #-----------------------------------------------------------------------------

    #-----------------------------------------------------------------------------
    # Imports
    #-----------------------------------------------------------------------------
    #from __future__ import print_function

    import inspect
    #import os
    #import re
    #import sys

    try:
        # Python >= 3.3
        from importlib.machinery import all_suffixes
        _suffixes = all_suffixes()
    except ImportError:
        from imp import get_suffixes
        _suffixes = [ s[0] for s in get_suffixes() ]

    # Third-party imports
    from time import time
    from zipimport import zipimporter

    TIMEOUT_STORAGE = 2

    TIMEOUT_GIVEUP = 20

    # Regular expression for the python import statement
    import_re = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*?)'
                           r'(?P<package>[/\\]__init__)?'
                           r'(?P<suffix>%s)$' %
                           r'|'.join(re.escape(s) for s in _suffixes))

    # RE for the ipython %run command (python + ipython scripts)
    magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$')

    def module_list(path):
        """
        Return the list containing the names of the modules available in the given
        folder.
        """
        # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
        if path == '':
            path = '.'

        # A few local constants to be used in loops below
        pjoin = os.path.join

        if os.path.isdir(path):
            # Build a list of all files in the directory and all files
            # in its subdirectories. For performance reasons, do not
            # recurse more than one level into subdirectories.
            files = []
            for root, dirs, nondirs in os.walk(path):
                subdir = root[len(path)+1:]
                if subdir:
                    files.extend(pjoin(subdir, f) for f in nondirs)
                    dirs[:] = [] # Do not recurse into additional subdirectories.
                else:
                    files.extend(nondirs)

        else:
            try:
                files = list(zipimporter(path)._files.keys())
            except:
                files = []

        # Build a list of modules which match the import_re regex.
        modules = []
        for f in files:
            m = import_re.match(f)
            if m:
                modules.append(m.group('name'))
        return list(set(modules))


    def get_root_modules():
        """
        Returns a list containing the names of all the modules available in the
        folders of the pythonpath.

        ip.db['rootmodules_cache'] maps sys.path entries to list of modules.
        """
        #ip = get_ipython()
        #rootmodules_cache = ip.db.get('rootmodules_cache', {})
        rootmodules_cache = {}
        rootmodules = list(sys.builtin_module_names)
        start_time = time()
        #store = False
        for path in sys.path:
            try:
                modules = rootmodules_cache[path]
            except KeyError:
                modules = module_list(path)
                try:
                    modules.remove('__init__')
                except ValueError:
                    pass
                if path not in ('', '.'): # cwd modules should not be cached
                    rootmodules_cache[path] = modules
                if time() - start_time > TIMEOUT_STORAGE and not store:
                    #store = True
                    #print("\nCaching the list of root modules, please wait!")
                    #print("(This will only be done once - type '%rehashx' to "
                          #"reset cache!)\n")
                    sys.stdout.flush()
                if time() - start_time > TIMEOUT_GIVEUP:
                    print("This is taking too long, we give up.\n")
                    return []
            rootmodules.extend(modules)
        #if store:
            #ip.db['rootmodules_cache'] = rootmodules_cache
        rootmodules = list(set(rootmodules))
        return rootmodules


    def is_importable(module, attr, only_modules):
        if only_modules:
            return inspect.ismodule(getattr(module, attr))
        else:
            return not(attr[:2] == '__' and attr[-2:] == '__')


    def try_import(mod, only_modules=False):
        try:
            m = __import__(mod)
        except:
            return []
        mods = mod.split('.')
        for module in mods[1:]:
            m = getattr(m, module)

        m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__

        completions = []
        if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
            completions.extend( [attr for attr in dir(m) if
                                 is_importable(m, attr, only_modules)])

        completions.extend(getattr(m, '__all__', []))
        if m_is_init:
            completions.extend(module_list(os.path.dirname(m.__file__)))
        completions = set(completions)
        if '__init__' in completions:
            completions.remove('__init__')
        return list(completions)


    def module_completion(line):
        """
        Returns a list containing the completion possibilities for an import line.

        The line looks like this :
        'import xml.d'
        'from xml.dom import'
        """

        words = line.split(' ')
        nwords = len(words)

        # from whatever <tab> -> 'import '
        if nwords == 3 and words[0] == 'from':
            return ['import ']

        # 'from xy<tab>' or 'import xy<tab>'
        if nwords < 3 and (words[0] in ['import','from']) :
            if nwords == 1:
                return get_root_modules()
            mod = words[1].split('.')
            if len(mod) < 2:
                return get_root_modules()
            completion_list = try_import('.'.join(mod[:-1]), True)
            return ['.'.join(mod[:-1] + [el]) for el in completion_list]

        # 'from xyz import abc<tab>'
        if nwords >= 3 and words[0] == 'from':
            mod = words[1]
            return try_import(mod)

    return module_completion, module_list


def main():
    input = sys.argv[1:]
    if len(input) == 0:
        return
    elif '<' in input or '>' in input:
        print('_longopt')
        return
    options = list(set(parse_string(input)))

    if ' ' in input[-1] and max(map(len, options)) + 1 >= len(input[-1]):
        options.append(input[-1].split(' ')[-1])

    if len(options) <= 1:
        options = options + [x + "'" for x in options]
    print(' '.join(options))


if __name__ == '__main__':
    main()
