"""Base class for GLU callback-caching structures"""
import ctypes
import weakref

class GLUStruct( object ):
	"""Mix-in class for GLU Structures that want to retain references to callbacks
	
	Also provides original-object-return for the "datapointer" style paremters
	
	Each sub-class must override:
		CALLBACK_TYPES -- maps a "which" constant to a function type 
		CALLBACK_FUNCTION_REGISTRARS -- maps a "which" constant to the 
			registration function for functions of that type
		WRAPPER_METHODS -- maps a "which" consant to a method of the structure 
			that produces a callable around the function which takes care of 
			input/output arguments, data conversions, error handling and the 
			like.
	Creates a dictionary member dataPointers if original-object-return is used
	Creates a dictionary member callbacks if callback registration is used
	"""
	def getAsParam( self ):
		"""Gets as a ctypes pointer to the underlying structure"""
		return ctypes.pointer( self )
	_as_parameter_ = property( getAsParam )
	CALLBACK_TYPES = None
	CALLBACK_FUNCTION_REGISTRARS = None
	WRAPPER_METHODS = None
	def noteObject( self, object ):
		"""Note object for later retrieval as a Python object pointer
		
		This is the registration point for "original object return", returns 
		a void pointer to the Python object, though this is, effectively, an 
		opaque value.
		"""
		identity = id(object)
		try:
			self.dataPointers[ identity ] = object
		except AttributeError, err:
			self.dataPointers = { identity: object }
		return identity
	def originalObject( self, voidPointer ):
		"""Given a void-pointer, try to find our original Python object"""
		if isinstance( voidPointer, (int,long)):
			identity = voidPointer
		elif voidPointer is None:
			return None
		else:
			try:
				identity = voidPointer.value 
			except AttributeError, err:
				identity = voidPointer[0]
		try:
			return self.dataPointers[ identity ]
		except (KeyError,AttributeError), err:
			return voidPointer
	def addCallback( self, which, function ):
		"""Register a callback for this structure object"""
		callbackType = self.CALLBACK_TYPES.get( which )
		if not callbackType:
			raise ValueError(
				"""Don't have a registered callback type for %r"""%(
					which,
				)
			)
		wrapperMethod = self.WRAPPER_METHODS.get( which )
		if wrapperMethod is not None:
			function = getattr(self,wrapperMethod)( function )
		cCallback = callbackType( function )
		# XXX this is ugly, query to ctypes list on how to fix it...
		try:
			self.CALLBACK_FUNCTION_REGISTRARS[which]( self, which, cCallback )
		except ctypes.ArgumentError, err:
			err.args += (which,cCallback)
			raise
		#gluTessCallbackBase( self, which, cCallback)
		# XXX catch errors!
		if getattr( self, 'callbacks', None ) is None:
			self.callbacks = {}
		self.callbacks[ which ] = cCallback
		return cCallback
	def ptrAsArray( self, ptr, length, type ):
		"""Copy length values from ptr into new array of given type"""
		result = type.zeros( (length,) )
		for i in range(length):
			result[i] = ptr[i]
		return result
