from bgl import *
from . import buffer_utils
from .gl_utils import gl_utils

G_orphaned_vaos = set()

def clear_orphaned_vaos():
    _orp_vaos = []
    for vao in G_orphaned_vaos:
        if glIsVertexArray(vao):
            _orp_vaos.append(vao)
    if _orp_vaos:
        G_orphaned_vaos.difference_update(_orp_vaos)
        _buf = Buffer(GL_INT, len(_orp_vaos), _orp_vaos)
        glDeleteVertexArrays(len(_orp_vaos), _buf)


class GLBatch():
    def __init__(self, prim_type, vbuf: buffer_utils.GLVertBuf, ibuf=None) -> None:
        self._prim_type = prim_type
        self._vbuf = vbuf
        self._ibuf = ibuf
        self._int_buf = Buffer(GL_INT, 5)
        self._vao = 0
        self._shader = None

    def bind(self):
        if self._vao == 0 or not glIsVertexArray(self._vao):
            clear_orphaned_vaos()
            assert self._shader
            glGenVertexArrays(1, self._int_buf)
            self._vao = self._int_buf[0]
            vaos = []
            while self._vao <= 10:
                vaos.append(self._vao)
                glGenVertexArrays(1, self._int_buf)
                self._vao = self._int_buf[0]
                if len(vaos) > 10:
                    break
            for vao in vaos:
                self._int_buf[0] = vao
                glDeleteVertexArrays(1, self._int_buf)
            attrs = self._shader.get_attrib_locations()
            gl_utils.set_vertex_array_binding(self._vao, self._vbuf, self._ibuf, attrs)

        glBindVertexArray(self._vao)

    def draw(self, shader, v_first=0, v_count=0):
        shader.bind()
        self._shader = shader
        self.bind()

        if v_count == 0:
            if self._ibuf:
                v_count = self._ibuf.len()
            else:
                v_count = self._vbuf.len()

        if self._ibuf:
            glEnable(GL_PRIMITIVE_RESTART)
            gl_utils.set_primitive_restart_index()
            glDrawElements(self._prim_type, v_count, GL_UNSIGNED_INT, 0)
        elif self._vbuf:
            glDrawArrays(self._prim_type, v_first, v_count)
        glBindVertexArray(0)

    def __del__(self):
        if self._vao != 0:
            if not glIsVertexArray(self._vao):
                G_orphaned_vaos.add(self._vao)
            else:
                self._int_buf[0] = self._vao
                glDeleteVertexArrays(1, self._int_buf)
