# Utility function for wrapping objects.  Centralising allows me to turn
# debugging on and off for the entire package in a single spot.

import sys
import win32com.server.util
from win32com.server.exception import Exception
import winerror
import win32api
import os

try:
	os.environ["DEBUG_AXDEBUG"]
	debugging = 1
except KeyError:
	debugging = 0

def trace(*args):
	if not debugging: return
	print str(win32api.GetCurrentThreadId()) + ":",
	for arg in args:
		print arg,
	print

# The AXDebugging implementation assumes that the returned COM pointers are in
# some cases identical.  Eg, from a C++ perspective:
# p->GetSomeInterface( &p1 );
# p->GetSomeInterface( &p2 );
# p1==p2
# By default, this is _not_ true for Python.
# (Now this is only true for Document objects, and Python
# now does ensure this.

all_wrapped = {} 

def _wrap_nodebug(object, iid):
	return win32com.server.util.wrap(object, iid)

def _wrap_debug(object, iid):
	import win32com.server.policy
	dispatcher = win32com.server.policy.DispatcherWin32trace
	return win32com.server.util.wrap(object, iid, useDispatcher = dispatcher)

if debugging:
	_wrap = _wrap_debug
else:
	_wrap = _wrap_nodebug

def _wrap_remove(object, iid = None):
	# Old - no longer used or necessary!
	return

def _dump_wrapped():
	from win32com.server.util import unwrap
	print "Wrapped items:"
	for key, items in all_wrapped.items():
		print key,
		try:
			ob = unwrap(key)
			print ob, sys.getrefcount(ob)
		except:
			print "<error>"


def RaiseNotImpl(who = None):
	if who is not None:
		print "********* Function %s Raising E_NOTIMPL  ************" % (who)

	# Print a sort-of "traceback", dumping all the frames leading to here.		
	try:
		1/0
	except:
		frame = sys.exc_info()[2].tb_frame
	while frame:
		print "File: %s, Line: %d" % (frame.f_code.co_filename, frame.f_lineno)
		frame = frame.f_back
	
	# and raise the exception for COM
	raise Exception(scode=winerror.E_NOTIMPL)
		

import win32com.server.policy
class Dispatcher(win32com.server.policy.DispatcherWin32trace):
	def __init__(self, policyClass, object):
		win32com.server.policy.DispatcherTrace.__init__(self, policyClass, object)
		import win32traceutil # Sets up everything.
#		print "Object with win32trace dispatcher created (object=%s)" % `object`

	def _QueryInterface_(self, iid):
		rc = win32com.server.policy.DispatcherBase._QueryInterface_(self, iid)
#		if not rc:
#			self._trace_("in _QueryInterface_ with unsupported IID %s (%s)\n" % (IIDToInterfaceName(iid),iid))
		return rc

	def _Invoke_(self, dispid, lcid, wFlags, args):
		print "In Invoke with", dispid, lcid, wFlags, args, "with object",self.policy._obj_
		try:
			rc = win32com.server.policy.DispatcherBase._Invoke_(self, dispid, lcid, wFlags, args)
#			print "Invoke of", dispid, "returning", rc
			return rc
		except Exception:
			t, v, tb = sys.exc_info()
			tb = None # A cycle
			scode = v.scode
			try:
				desc = " (" + str(v.description) + ")"
			except AttributeError:
				desc = ""
			print "*** Invoke of %s raised COM exception 0x%x%s" % (dispid, scode, desc)
		except:
			print "*** Invoke of %s failed:" % dispid
			typ, val, tb = sys.exc_info()
			import traceback
			traceback.print_exception(typ, val, tb)
			raise typ, val, tb

