# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
# -----------------------------------------------------------------------------

import os
import sys
import re
import json
import weakref
from distutils.version import LooseVersion

import numpy as np

from . import gl
from ..util import logger

# TODO: expose these via an extension space in .gl?
_internalformats: list = ...
_internalformats = ...

# Value to mark a glir object that was just deleted. So we can safely
# ignore it (and not raise an error that the object could not be found).
# This can happen e.g. if A is created, A is bound to B and then A gets
# deleted. The commands may get executed in order: A gets created, A
# gets deleted, A gets bound to B.
JUST_DELETED: str = ...

def as_enum(enum): ...

class _GlirQueueShare(object):
    def __init__(self, queue): ...
    def command(self, *args): ...
    def set_verbose(self, verbose): ...
    def show(self, filter=None): ...
    def clear(self): ...
    def flush(self, parser): ...
    def _filter(self, commands, parser): ...

class GlirQueue(object):
    def __init__(self): ...
    def command(self, *args): ...
    def set_verbose(self, verbose): ...
    def clear(self): ...
    def associate(self, queue): ...
    def flush(self, parser): ...

def _convert_es2_shader(shader): ...
def _convert_desktop_shader(shader): ...
def convert_shader(backend_type, shader): ...
def as_es2_command(command): ...

class BaseGlirParser(object):
    def __init__(self): ...
    def is_remote(self): ...
    @property
    def shader_compatibility(self): ...
    def parse(self, commands): ...

class GlirParser(BaseGlirParser):
    def __init__(self): ...
    @property
    def shader_compatibility(self): ...
    def is_remote(self): ...
    def _parse(self, command): ...
    def parse(self, commands): ...
    def get_object(self, id_): ...
    def _gl_initialize(self): ...

def glir_logger(parser_cls, file_or_filename): ...

# GLIR objects

class GlirObject(object):
    def __init__(self, parser, id_): ...
    @property
    def handle(self): ...
    @property
    def id(self): ...
    def __repr__(self): ...

class GlirShader(GlirObject):
    _target: None = ...

    def create(self): ...
    def set_data(self, offset, code): ...
    def delete(self): ...
    def _get_error(self, code, errors, indentation=0): ...
    def _parse_error(self, error): ...

class GlirVertexShader(GlirShader):
    _target = ...

class GlirFragmentShader(GlirShader):
    _target = ...

class GlirGeometryShader(GlirShader):
    # _target assignment must be delayed because GL_GEOMETRY_SHADER does not
    # exist until the user calls use_gl('gl+')
    _target: None = ...

    def __init__(self, *args, **kwargs): ...

class GlirProgram(GlirObject):

    UTYPEMAP: dict = ...

    ATYPEMAP: dict = ...

    ATYPEINFO: dict = ...

    def create(self): ...
    def delete(self): ...
    def activate(self): ...
    def deactivate(self): ...
    def set_shaders(self, vert, frag): ...
    def attach(self, id_): ...
    def link_program(self): ...
    def _get_active_attributes_and_uniforms(self): ...
    def set_texture(self, name, value): ...
    def set_uniform(self, name, type_, value): ...
    def set_attribute(self, name, type_, value): ...
    def _pre_draw(self): ...
    def _validate(self): ...
    def _post_draw(self): ...
    def draw(self, mode, selection): ...

class GlirBuffer(GlirObject):
    _target: None = ...
    _usage = ...  # STATIC_DRAW, STREAM_DRAW or DYNAMIC_DRAW

    def create(self): ...
    def delete(self): ...
    def activate(self): ...
    def deactivate(self): ...
    def set_size(self, nbytes): ...
    def set_data(self, offset, data): ...

class GlirVertexBuffer(GlirBuffer):
    _target = ...

class GlirIndexBuffer(GlirBuffer):
    _target = ...

class GlirTexture(GlirObject):
    _target: None = ...

    _types: dict = ...

    def create(self): ...
    def delete(self): ...
    def activate(self): ...
    def deactivate(self): ...

    # Taken from pygly
    def _get_alignment(self, width): ...
    def set_wrapping(self, wrapping): ...
    def set_interpolation(self, min, mag): ...

# these should be auto generated in _constants.py. But that doesn't seem
# to be happening. TODO - figure out why the C parser in (createglapi.py)
# is not extracting these constanst out.
# found the constant value at:
# http://docs.factorcode.org/content/word-GL_TEXTURE_1D,opengl.gl.html
# http://docs.factorcode.org/content/word-GL_SAMPLER_1D%2Copengl.gl.html
GL_SAMPLER_1D = ...
GL_TEXTURE_1D = ...

class GlirTexture1D(GlirTexture):
    _target = ...

    def set_size(self, shape, format, internalformat): ...
    def set_data(self, offset, data): ...

class GlirTexture2D(GlirTexture):
    _target = ...

    def set_size(self, shape, format, internalformat): ...
    def set_data(self, offset, data): ...

GL_SAMPLER_3D = ...
GL_TEXTURE_3D = ...

USE_TEX_3D: bool = ...

def _check_pyopengl_3D(): ...
def glTexImage3D(target, level, internalformat, format, type, pixels): ...
def glTexImage1D(target, level, internalformat, format, type, pixels): ...
def glTexSubImage1D(target, level, xoffset, format, type, pixels): ...
def glTexSubImage3D(target, level, xoffset, yoffset, zoffset, format, type, pixels): ...

class GlirTexture3D(GlirTexture):
    _target = ...

    def set_size(self, shape, format, internalformat): ...
    def set_data(self, offset, data): ...

class GlirTextureCube(GlirTexture):
    _target = ...
    _cube_targets: list = ...

    def set_size(self, shape, format, internalformat): ...
    def set_data(self, offset, data): ...

class GlirRenderBuffer(GlirObject):
    def create(self): ...
    def delete(self): ...
    def activate(self): ...
    def deactivate(self): ...
    def set_size(self, shape, format): ...

class GlirFrameBuffer(GlirObject):

    # todo: on ES 2.0 -> gl.gl_RGBA4
    _formats: dict = ...

    def create(self): ...
    def delete(self): ...
    def set_framebuffer(self, yes): ...
    def activate(self): ...
    def deactivate(self): ...
    def attach(self, attachment, buffer_id): ...
    def _validate(self): ...
