'''
Kivy framework
==============

Kivy is an open source library for developing multi-touch applications. It is
cross-platform (Linux/OSX/Windows/Android/iOS) and released under
the terms of the `MIT License <https://en.wikipedia.org/wiki/MIT_License>`_.

It comes with native support for many multi-touch input devices, a growing
library of multi-touch aware widgets and hardware accelerated OpenGL drawing.
Kivy is designed to let you focus on building custom and highly interactive
applications as quickly and easily as possible.

With Kivy, you can take full advantage of the dynamic nature of Python. There
are thousands of high-quality, free libraries that can be integrated in your
application. At the same time, performance-critical parts are implemented
using `Cython <http://cython.org/>`_.

See http://kivy.org for more information.
'''

__all__ = (
    'require', 'parse_kivy_version',
    'kivy_configure', 'kivy_register_post_configuration',
    'kivy_options', 'kivy_base_dir',
    'kivy_modules_dir', 'kivy_data_dir', 'kivy_shader_dir',
    'kivy_icons_dir', 'kivy_home_dir',
    'kivy_config_fn', 'kivy_usermodules_dir',
)

import sys
import shutil
from getopt import getopt, GetoptError
from os import environ, mkdir
from os.path import dirname, join, basename, exists, expanduser
import pkgutil
import re
from kivy.logger import Logger, LOG_LEVELS
from kivy.utils import platform

MAJOR = 2
MINOR = 0
MICRO = 0
RELEASE = False

__version__ = '%d.%d.%d' % (MAJOR, MINOR, MICRO)

if not RELEASE:
    # if it's a rcx release, it's not proceeded by a period. If it is a
    # devx release, it must start with a period
    __version__ += '.dev0'

try:
    from kivy.version import __hash__, __date__
    __hash__ = __hash__[:7]
except ImportError:
    __hash__ = __date__ = ''

# internals for post-configuration
__kivy_post_configuration = []


if platform == 'macosx' and sys.maxsize < 9223372036854775807:
    r = '''Unsupported Python version detected!:
    Kivy requires a 64 bit version of Python to run on OS X. We strongly
    advise you to use the version of Python that is provided by Apple
    (don't use ports, fink or homebrew unless you know what you're
    doing).
    See http://kivy.org/docs/installation/installation-macosx.html for
    details.
    '''
    Logger.critical(r)

if sys.version_info[0] == 2:
    Logger.critical(
        'Unsupported Python version detected!: Kivy 2.0.0 and higher does not '
        'support Python 2. Please upgrade to Python 3, or downgrade Kivy to '
        '1.11.0 - the last Kivy release that still supports Python 2.')


def parse_kivy_version(version):
    """Parses the kivy version as described in :func:`require` into a 3-tuple
    of ([x, y, z], 'rc|a|b|dev|post', 'N') where N is the tag revision. The
    last two elements may be None.
    """
    m = re.match(
        '^([0-9]+)\\.([0-9]+)\\.([0-9]+?)(rc|a|b|\\.dev|\\.post)?([0-9]+)?$',
        version)
    if m is None:
        raise Exception('Revision format must be X.Y.Z[-tag]')

    major, minor, micro, tag, tagrev = m.groups()
    if tag == '.dev':
        tag = 'dev'
    if tag == '.post':
        tag = 'post'
    return [int(major), int(minor), int(micro)], tag, tagrev


def require(version):
    '''Require can be used to check the minimum version required to run a Kivy
    application. For example, you can start your application code like this::

        import kivy
        kivy.require('1.0.1')

    If a user attempts to run your application with a version of Kivy that is
    older than the specified version, an Exception is raised.

    The Kivy version string is built like this::

        X.Y.Z[tag[tagrevision]]

        X is the major version
        Y is the minor version
        Z is the bugfixes revision

    The tag is optional, but may be one of '.dev', '.post', 'a', 'b', or 'rc'.
    The tagrevision is the revision number of the tag.

    .. warning::

        You must not ask for a version with a tag, except -dev. Asking for a
        'dev' version will just warn the user if the current Kivy
        version is not a -dev, but it will never raise an exception.
        You must not ask for a version with a tagrevision.

    '''

    # user version
    revision, tag, tagrev = parse_kivy_version(version)
    # current version
    sysrevision, systag, systagrev = parse_kivy_version(__version__)

    if tag and not systag:
        Logger.warning('Application requested a dev version of Kivy. '
                       '(You have %s, but the application requires %s)' % (
                           __version__, version))
    # not tag rev (-alpha-1, -beta-x) allowed.
    if tagrev is not None:
        raise Exception('Revision format must not contain any tagrevision')

    # finally, checking revision
    if sysrevision < revision:
        raise Exception('The version of Kivy installed on this system '
                        'is too old. '
                        '(You have %s, but the application requires %s)' % (
                            __version__, version))


def kivy_configure():
    '''Call post-configuration of Kivy.
    This function must be called if you create the window yourself.
    '''
    for callback in __kivy_post_configuration:
        callback()


def get_includes():
    '''Retrieves the directories containing includes needed to build new Cython
    modules with Kivy as a dependency. Currently returns the location of the
    kivy.graphics module.

    .. versionadded:: 1.9.1
    '''
    root_dir = dirname(__file__)
    return [join(root_dir, 'graphics'), join(root_dir, 'tools', 'gles_compat'),
            join(root_dir, 'include')]


def kivy_register_post_configuration(callback):
    '''Register a function to be called when kivy_configure() is called.

    .. warning::
        Internal use only.
    '''
    __kivy_post_configuration.append(callback)


def kivy_usage():
    '''Kivy Usage: %s [OPTION...]::

        -h, --help
            Prints this help message.
        -d, --debug
            Shows debug log.
        -a, --auto-fullscreen
            Force 'auto' fullscreen mode (no resolution change).
            Uses your display's resolution. This is most likely what you want.
        -c, --config section:key[:value]
            Set a custom [section] key=value in the configuration object.
        -f, --fullscreen
            Force running in fullscreen mode.
        -k, --fake-fullscreen
            Force 'fake' fullscreen mode (no window border/decoration).
            Uses the resolution specified by width and height in your config.
        -w, --windowed
            Force running in a window.
        -p, --provider id:provider[,options]
            Add an input provider (eg: ccvtable1:tuio,192.168.0.1:3333).
        -m mod, --module=mod
            Activate a module (use "list" to get a list of available modules).
        -r, --rotation
            Rotate the window's contents (0, 90, 180, 270).
        -s, --save
            Save current Kivy configuration.
        --size=640x480
            Size of window geometry.
        --dpi=96
            Manually overload the Window DPI (for testing only.)
    '''
    print(kivy_usage.__doc__ % (basename(sys.argv[0])))


#: Global settings options for kivy
kivy_options = {
    'window': ('egl_rpi', 'sdl2', 'pygame', 'sdl', 'x11'),
    'text': ('pil', 'sdl2', 'pygame', 'sdlttf'),
    'video': (
        'gstplayer', 'ffmpeg', 'ffpyplayer', 'null'),
    'audio': (
        'gstplayer', 'pygame', 'ffpyplayer', 'sdl2',
        'avplayer'),
    'image': ('tex', 'imageio', 'dds', 'sdl2', 'pygame', 'pil', 'ffpy', 'gif'),
    'camera': ('opencv', 'gi', 'avfoundation',
               'android', 'picamera'),
    'spelling': ('enchant', 'osxappkit', ),
    'clipboard': (
        'android', 'winctypes', 'xsel', 'xclip', 'dbusklipper', 'nspaste',
        'sdl2', 'pygame', 'dummy', 'gtk3', )}

# Read environment
for option in kivy_options:
    key = 'KIVY_%s' % option.upper()
    if key in environ:
        try:
            if type(kivy_options[option]) in (list, tuple):
                kivy_options[option] = environ[key].split(',')
            else:
                kivy_options[option] = environ[key].lower() in \
                    ('true', '1', 'yes')
        except Exception:
            Logger.warning('Core: Wrong value for %s environment key' % key)
            Logger.exception('')

# Extract all needed path in kivy
#: Kivy directory
kivy_base_dir = dirname(sys.modules[__name__].__file__)
#: Kivy modules directory

kivy_modules_dir = environ.get('KIVY_MODULES_DIR',
                               join(kivy_base_dir, 'modules'))
#: Kivy data directory
kivy_data_dir = environ.get('KIVY_DATA_DIR',
                            join(kivy_base_dir, 'data'))
#: Kivy binary deps directory
kivy_binary_deps_dir = environ.get('KIVY_BINARY_DEPS',
                                   join(kivy_base_dir, 'binary_deps'))
#: Kivy glsl shader directory
kivy_shader_dir = join(kivy_data_dir, 'glsl')
#: Kivy icons config path (don't remove the last '')
kivy_icons_dir = join(kivy_data_dir, 'icons', '')
#: Kivy user-home storage directory
kivy_home_dir = ''
#: Kivy configuration filename
kivy_config_fn = ''
#: Kivy user modules directory
kivy_usermodules_dir = ''

# if there are deps, import them so they can do their magic.
import kivy.deps
_packages = []
for importer, modname, ispkg in pkgutil.iter_modules(kivy.deps.__path__):
    if not ispkg:
        continue
    if modname.startswith('gst'):
        _packages.insert(0, (importer, modname, 'kivy.deps'))
    else:
        _packages.append((importer, modname, 'kivy.deps'))

try:
    import kivy_deps
    for importer, modname, ispkg in pkgutil.iter_modules(kivy_deps.__path__):
        if not ispkg:
            continue
        if modname.startswith('gst'):
            _packages.insert(0, (importer, modname, 'kivy_deps'))
        else:
            _packages.append((importer, modname, 'kivy_deps'))
except ImportError:
    pass

_logging_msgs = []
for importer, modname, package in _packages:
    try:
        mod = importer.find_module(modname).load_module(modname)

        version = ''
        if hasattr(mod, '__version__'):
            version = ' {}'.format(mod.__version__)
        _logging_msgs.append(
            'deps: Successfully imported "{}.{}"{}'.
            format(package, modname, version))
    except ImportError as e:
        Logger.warning(
            'deps: Error importing dependency "{}.{}": {}'.
            format(package, modname, str(e)))

# Don't go further if we generate documentation
if any(name in sys.argv[0] for name in ('sphinx-build', 'autobuild.py')):
    environ['KIVY_DOC'] = '1'
if 'sphinx-build' in sys.argv[0]:
    environ['KIVY_DOC_INCLUDE'] = '1'
if any(('nosetests' in arg or 'pytest' in arg) for arg in sys.argv):
    environ['KIVY_UNITTEST'] = '1'
if any('pyinstaller' in arg.lower() for arg in sys.argv):
    environ['KIVY_PACKAGING'] = '1'

if not environ.get('KIVY_DOC_INCLUDE'):
    # Configuration management
    if 'KIVY_HOME' in environ:
        kivy_home_dir = expanduser(environ['KIVY_HOME'])
    else:
        user_home_dir = expanduser('~')
        if platform == 'android':
            user_home_dir = environ['ANDROID_APP_PATH']
        elif platform == 'ios':
            user_home_dir = join(expanduser('~'), 'Documents')
        kivy_home_dir = join(user_home_dir, '.kivy')

    kivy_config_fn = join(kivy_home_dir, 'config.ini')
    kivy_usermodules_dir = join(kivy_home_dir, 'mods')
    icon_dir = join(kivy_home_dir, 'icon')

    if 'KIVY_NO_CONFIG' not in environ:
        if not exists(kivy_home_dir):
            mkdir(kivy_home_dir)
        if not exists(kivy_usermodules_dir):
            mkdir(kivy_usermodules_dir)