""" Management of documents for AXDebugging.
"""

import axdebug, gateways
import pythoncom
from util import _wrap, _wrap_remove, RaiseNotImpl, trace
from win32com.server.util import unwrap
import codecontainer
import contexts
from win32com.server.exception import Exception
import win32api, winerror, os, string, sys

#def trace(*args):
#	pass

def GetGoodFileName(fname):
	if fname[0] <> "<":
		return win32api.GetFullPathName(fname)
	return fname

class DebugDocumentProvider(gateways.DebugDocumentProvider):
	def __init__(self, doc):
		self.doc = doc

	def GetName(self, dnt):
		return self.doc.GetName(dnt)

	def GetDocumentClassId(self):
		return self.doc.GetDocumentClassId()
	
	def GetDocument(self):
		return self.doc

class DebugDocumentText(gateways.DebugDocumentInfo, gateways.DebugDocumentText, gateways.DebugDocument):
	_com_interfaces_ = gateways.DebugDocumentInfo._com_interfaces_ + \
	                   gateways.DebugDocumentText._com_interfaces_ + \
	                   gateways.DebugDocument._com_interfaces_
	_public_methods_ = gateways.DebugDocumentInfo._public_methods_ + \
	                   gateways.DebugDocumentText._public_methods_ + \
	                   gateways.DebugDocument._public_methods_
	# A class which implements a DebugDocumentText, using the functionality
	# provided by a codeContainer
	def __init__(self, codeContainer):
		gateways.DebugDocumentText.__init__(self)
		gateways.DebugDocumentInfo.__init__(self)
		gateways.DebugDocument.__init__(self)
		self.codeContainer = codeContainer
		
	def _Close(self):
		self.docContexts = None
#		self.codeContainer._Close()
		self.codeContainer = None
	# IDebugDocumentInfo
	def GetName(self, dnt):
		return self.codeContainer.GetName(dnt)

	def GetDocumentClassId(self):
		return "{DF630910-1C1D-11d0-AE36-8C0F5E000000}"

	# IDebugDocument has no methods!
	#

	# IDebugDocumentText methods.
	# def GetDocumentAttributes
	def GetSize(self):
#		trace("GetSize")
		return self.codeContainer.GetNumLines(), self.codeContainer.GetNumChars()
	def GetPositionOfLine(self, cLineNumber):
		return self.codeContainer.GetPositionOfLine(cLineNumber)
	def GetLineOfPosition(self, charPos):
		return self.codeContainer.GetLineOfPosition(charPos)
	def GetText(self, charPos, maxChars, wantAttr):
		# Get all the attributes, else the tokenizer will get upset.
		# XXX - not yet!
#		trace("GetText", charPos, maxChars, wantAttr)
		cont = self.codeContainer
		attr = cont.GetSyntaxColorAttributes()
		return cont.GetText(), attr

	def GetPositionOfContext(self, context):
		trace("GetPositionOfContext", context)
		context = unwrap(context)
		return context.offset, context.length

	# Return a DebugDocumentContext.
	def GetContextOfPosition(self, charPos, maxChars):
		# Make one
		doc = _wrap(self, axdebug.IID_IDebugDocument)
		rc = self.codeContainer.GetCodeContextAtPosition(charPos)
		return rc.QueryInterface(axdebug.IID_IDebugDocumentContext)

class CodeContainerProvider:
	"""An abstract Python class which provides code containers!
	
	Given a Python file name (as the debugger knows it by) this will
	return a CodeContainer interface suitable for use.
	
	This provides a simple base imlpementation that simply supports
	a dictionary of nodes and providers.
	"""
	def __init__(self):
		self.ccsAndNodes = {}
	
	def AddCodeContainer(self, cc, node = None):
		fname = GetGoodFileName(cc.fileName)
		self.ccsAndNodes[fname] = cc, node

	def FromFileName(self, fname):
		cc, node = self.ccsAndNodes.get(GetGoodFileName(fname), (None, None))
#		if cc is None:
#			print "FromFileName for %s returning None" % fname
		return cc

	def Close(self):
		for cc, node in self.ccsAndNodes.values():
			try:
				# Must close the node before closing the provider
				# as node may make calls on provider (eg Reset breakpoints etc)
				if node is not None:
					node.Close()
				cc._Close()
			except pythoncom.com_error:
				pass
		self.ccsAndNodes = {}
