#!/usr/bin/env python

# Always prefer setuptools over distutils
import os, imp, sys
from setuptools import setup, find_packages
import inspect
import re

import distutils.cmd

__doc__ = """

To install as system package:

  python setup.py install

To install as local package, just run:

  mkdir /tmp/builds/
  python setup.py install --root=/tmp/builds
  /tmp/builds/usr/bin/$DS -? -v4

To tune some options:

  RU=/opt/control
  python setup.py egg_info --egg-base=tmp install --root=$RU/files --no-compile \
    --install-lib=lib/python/site-packages --install-scripts=ds

-------------------------------------------------------------------------------
"""
try:
    # python3
    from builtins import str
except:
    pass

release = open('fandango/VERSION').read()

scripts = [
#    './fandango/scripts/ctds',
#    './fandango/scripts/csv2tango',
#    './fandango/scripts/tango2csv',
#    './fandango/scripts/tango2json',
#    './fandango/scripts/sardanact',
#    './fandango/scripts/tango_cleanup',
#    './fandango/scripts/folder-gui',
#    './fandango/scripts/fandango',
#    './fandango/scripts/DynamicDS',
#    './fandango/scripts/WorkerDS',
#    './fandango/scripts/CopyCatDS',
#    './fandango/scripts/FolderDS',
#    './fandango/scripts/tango_servers',
#    './fandango/scripts/tango_host',
#    './fandango/scripts/tango_property',
#    './fandango/scripts/tango_monitor',
]

entry_points = {
    'console_scripts': [
        # 'CopyCatDS = fandango.interface.CopyCatDS:main',
        # 'WorkerDS = fandango.device.WorkerDS:main',
    ],
}


class GenerateTestsCommand(distutils.cmd.Command):
    description = "Command to generate fandango tests based on their definitions"
    user_options = [
        # long option, short option, description
        ("test-folder-path=", None, "Path to tests folder."),
        ("test-files-suffix=", None, "All autogenerated tests files will have this prefix."),
    ]

    def initialize_options(self):
        self.test_folder_path = os.path.dirname(os.path.abspath(__file__)) + '/ci/tests'
        self.test_files_suffix = 'autogenerated'
        self.definitions_file_path = self.test_folder_path + '/definitions.py'

    def finalize_options(self):
        if os.path.isdir(self.test_folder_path) is False or os.path.isfile(self.definitions_file_path) is False:
            raise Exception("File definitions.py not found.")

    def run(self):
        """ This will generate tests for all definitions from definitions.py.
            Existing tests with name test_* in test folder will be reloaded. """
        # load test definitions
        sys.path.append(self.test_folder_path)
        import definitions
        # tests = { 'test_functional': { 'test_floor': { 'docs': 'Here's my doc', 'params': ((...), (...)) } }
        tests = {}
        for tested_function, test_defs in definitions.tests.items():
            test_filename, test_name = self.parse_test_name(tested_function)
            if test_filename not in tests:
                tests[test_filename] = {}
            for test_suffix, test_def in test_defs.items():
                tests[test_filename]['_'.join([test_name, test_suffix])] = test_def
        # generate new test files
        for filename, test_defs in tests.items():
            filename = filename.split(".")[:1]
            filename = "_".join(filename + [self.test_files_suffix]) + '.py'
            filepath = "/".join([self.test_folder_path, filename])
            with open(filepath, 'w') as f:
                content = self.tests_definitions(test_defs)
                f.write(content)
        print("Tests generated. Please verify output.")

    def parse_test_name(self, s):
        """ Takes fully qualified name of tested method/function name from definitions.py and returns test filename and test name. """
        splitted = re.sub('^fandango.','',s).split(".")
        file = "_".join(["test",  splitted[0]]) + '.py'
        test = "_".join(["test"] + splitted[1:])
        return file, test

    def tests_definitions(self, test_defs):
        """ Generates tests function definitions based on provided definition.
            Parameters
            ----------
            test_defs : Tests definitions. Eg. { test_name_with_suffix_1: {'docs': ..., 'params': ...} ... }
        """
        tests = ""
        for test_name, test_definition in test_defs.items():
            test = """\
def {}():
        \"\"\"{}\"\"\"
        params = {}
        for args, kwargs, init_args, init_kwargs, result in params:
        assert fandango.functional.avg(*args, **kwargs) == result
                    
""".format(test_name, test_definition['docs'], test_definition['params'])
            tests += test
        return tests


setup(
    name="fandango",
    version=str(release).strip(),
    packages=find_packages(),
    description="Simplify the configuration of big Tango control systems",
    long_description="Fandango is a Python module created to simplify the "
                     "configuration of big control systems; implementing the behavior of Jive "
                     "(configuration) and/or Astor (deployment) tools in methods that could "
                     "be called from scripts using regexp and wildcards. Fandango provides "
                     "functional methods, classes and utilities to develop high-level device "
                     "servers and APIs for Tango control system.",
    author="Sergi Rubio",
    author_email="srubio@cells.es",
    classifiers=[
        'Development Status :: 5 - Production/Stable',
        'Environment :: Other Environment',
        'Intended Audience :: Developers',
        'License :: OSI Approved :: ' \
        'GNU Lesser General Public License v3 or later (LGPLv3+)',
        'Natural Language :: English',
        'Operating System :: Microsoft :: Windows',
        'Operating System :: POSIX',
        'Operating System :: POSIX :: Linux',
        'Operating System :: Unix',
        'Programming Language :: Python',
        'Topic :: Scientific/Engineering',
        'Topic :: Software Development :: Libraries',
    ],
    platforms=["Linux,Windows XP/Vista/7/8"],
    # install_requires=[], #['python-future'],
    #scripts=scripts,
    entry_points=entry_points,
    include_package_data=False,
    zip_safe=False,
    python_requires='~=2.7',
    cmdclass={
        'generate_tests': GenerateTestsCommand,
    }
)
