"""Selection-buffer handling code

This code is resonsible for turning gluint *
arrays into structured representations for use
by Python-level code.
"""
from OpenGL._bytes import long, integer_types

def uintToLong( value ):
    if value < 0:
        # array type without a uint, so represented as an int 
        value = (value & 0x7fffffff) + 0x80000000
    return value

class GLSelectRecord( object ):
    """Minimalist object for storing an OpenGL selection-buffer record
    
    Provides near and far as *float* values by dividing by 
    self.DISTANCE_DIVISOR (2**32-1)
    From the spec:
        Depth values (which are in the range [0,1]) are multiplied by 
        2^32 - 1, before being placed in the hit record.
    
    Names are unmodified, so normally are slices of the array passed in 
    to GLSelectRecord.fromArray( array )
    """
    DISTANCE_DIVISOR = float((2**32)-1)
    __slots__ = ('near','far','names')
    def fromArray( cls, array, total ):
        """Produce list with all records from the array"""
        result = []
        index = 0
        arrayLength = len(array)
        for item in range( total ):
            if index + 2 >= arrayLength:
                break
            count = array[index]
            near = array[index+1]
            far = array[index+2]
            names = [ uintToLong(v) for v in array[index+3:index+3+count]]
            result.append(  cls( near, far, names ) )
            index += 3+count
        return result
    fromArray = classmethod( fromArray )
    
    def __init__( self, near, far, names ):
        """Initialise/store the values"""
        self.near = self.convertDistance( near )
        self.far = self.convertDistance( far )
        self.names = names 
    def convertDistance( self, value ):
        """Convert a distance value from array uint to 0.0-1.0 range float"""
        return uintToLong( value ) / self.DISTANCE_DIVISOR
    def __getitem__( self, key ):
        """Allow for treating the record as a three-tuple"""
        if isinstance( key, integer_types):
            return (self.near,self.far,self.names)[key]
        elif key in self.__slots__:
            try:
                return getattr( self, key )
            except AttributeError as err:
                raise KeyError( """Don't have an index/key %r for %s instant"""%(
                    key, self.__class__,
                ))
