"""Selection-buffer handling code

This code is resonsible for turning gluint *
arrays into structured representations for use
by Python-level code.
"""
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((2L**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 xrange( total ):
			if index + 2 >= arrayLength:
				break
			count = array[index]
			near = array[index+1]
			far = array[index+2]
			names = map(uintToLong, 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, (int,long)):
			return (self.near,self.far,self.names)[key]
		elif key in self.__slots__:
			try:
				return getattr( self, key )
			except AttributeError, err:
				raise KeyError( """Don't have an index/key %r for %s instant"""%(
					key, self.__class__,
				))
