#!/usr/bin/env python

"""
Uses the official Khronos-XML specs to generate a
GL/GLES/EGL/GLX/WGL Loader made for your needs. Glad currently supports
the languages C, D, Nim and Volt.
"""
from collections import namedtuple
import logging
import sys

from glad.opener import URLOpener
from glad.spec import SPECS
import glad.lang


Version = namedtuple('Version', ['major', 'minor'])

logger = logging.getLogger('glad')


def main():
    import os.path
    import argparse
    from argparse import ArgumentParser

    opener = URLOpener()

    def get_spec(value):
        if value not in SPECS:
            raise argparse.ArgumentTypeError('Unknown specification')

        spec_cls = SPECS[value]

        if os.path.exists(value + '.xml'):
            logger.info('using local specification: \'%s.xml\'', value)
            return spec_cls.from_file(value + '.xml')
        logger.info('getting \'%s\' specification from SVN', value)
        return spec_cls.from_svn(opener=opener)

    def ext_file(value):
        msg = 'Invalid extensions argument'
        if os.path.exists(value):
            msg = 'Invalid extensions file'
            try:
                with open(value, 'r') as f:
                    return f.read().split()
            except IOError:
                pass
        else:
            return [v.strip() for v in value.split(',') if v]

        raise argparse.ArgumentTypeError(msg)

    def version(value):
        if value is None or len(value.strip()) == 0:
            return None

        v = value
        if '.' not in v:
            v = '{}.0'.format(v)

        try:
            return Version(*map(int, v.split('.')))
        except ValueError:
            pass

        raise argparse.ArgumentTypeError('Invalid version: "{}"'.format(value))

    def cmdapi(value):
        try:
            return dict((p[0], version(p[1])) for p in
                        (list(map(str.strip, e.split('='))) for e in
                         filter(bool, map(str.strip, value.split(',')))))
        except IndexError:
            pass

        raise argparse.ArgumentTypeError(
            'Invalid api-string: "{}"'.format(value)
        )

    description = __doc__
    parser = ArgumentParser(description=description)

    parser.add_argument('--profile', dest='profile',
                        choices=['core', 'compatibility'],
                        default='compatibility',
                        help='OpenGL profile (defaults to compatibility)')
    parser.add_argument('--out-path', dest='out', required=True,
                        help='Output path for loader')
    parser.add_argument('--api', dest='api', type=cmdapi,
                        help='API type/version pairs, like "gl=3.2,gles=", '
                             'no version means latest')
    parser.add_argument('--generator', dest='generator', default='d',
                        choices=['c', 'c-debug', 'd', 'nim', 'volt'], required=True,
                        help='Language to generate the binding for')
    parser.add_argument('--extensions', dest='extensions',
                        default=None, type=ext_file,
                        help='Path to extensions file or comma separated '
                             'list of extensions, if missing '
                             'all extensions are included')
    parser.add_argument('--spec', dest='spec', default='gl',
                        choices=['gl', 'egl', 'glx', 'wgl'],
                        help='Name of the spec')
    parser.add_argument('--no-loader', dest='no_loader', action='store_true')
    parser.add_argument('--omit-khrplatform', dest='omit_khrplatform', action='store_true',
                        help='Omits inclusion of the khrplatform.h '
                        'file which is often unnecessary. '
                        'Only has an effect if used together '
                        'with c generators.')
    parser.add_argument('--local-files', dest='local_files', action='store_true',
                        help='Forces every file directly into the output '
                        'directory. No src or include subdirectories '
                        'are generated. '
                        'Only has an effect if used together '
                        'with c generators.')
    parser.add_argument('--quiet', dest='quiet', action='store_true')

    ns = parser.parse_args()

    if not ns.quiet:
        logging.basicConfig(
            format='[%(asctime)s][%(levelname)s\t][%(name)-7s\t]: %(message)s',
            datefmt='%m/%d/%Y %H:%M:%S', level=logging.DEBUG
        )

    spec = get_spec(ns.spec)
    if spec.NAME == 'gl':
        spec.profile = ns.profile

    api = ns.api
    if api is None or len(api.keys()) == 0:
        api = {spec.NAME: None}

    generator_cls, loader_cls = glad.lang.get_generator(
        ns.generator, spec.NAME.lower()
    )

    if loader_cls is None:
        return parser.error('API/Spec not yet supported')

    loader = loader_cls(api, disabled=ns.no_loader, local_files=ns.local_files)

    logger.info('generating \'%s\' bindings', spec.NAME)
    with generator_cls(
            ns.out,
            spec,
            api,
            ns.extensions,
            loader=loader,
            opener=opener,
            local_files=ns.local_files,
            omit_khrplatform=ns.omit_khrplatform
    ) as generator:
        generator.generate()

    logger.info('generating \'%s\' bindings - done', spec.NAME)

if __name__ == '__main__':
    main()
