# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

import os, sys, threading

import portage.const
from portage.util import writemsg

def set_trace(on=True):
	if on:
		t = trace_handler()
		threading.settrace(t.event_handler)
		sys.settrace(t.event_handler)
	else:
		sys.settrace(None)
		threading.settrace(None)

class trace_handler(object):

	def __init__(self):
		python_system_paths = []
		for x in sys.path:
			if os.path.basename(x).startswith("python2."):
				python_system_paths.append(x)

		self.ignore_prefixes = []
		for x in python_system_paths:
			self.ignore_prefixes.append(x + os.sep)

		self.trim_filename = prefix_trimmer(os.path.join(portage.const.PORTAGE_BASE_PATH, "pym") + os.sep).trim
		self.show_local_lines = False
		self.max_repr_length = 200

	def event_handler(self, *args):
		frame, event, arg = args
		if "line" == event:
			if self.show_local_lines:
				self.trace_line(*args)
		else:
			if not self.ignore_filename(frame.f_code.co_filename):
				self.trace_event(*args)
				return self.event_handler

	def trace_event(self, frame, event, arg):
		writemsg("%s line=%d name=%s event=%s %slocals=%s\n" % \
		(self.trim_filename(frame.f_code.co_filename),
		frame.f_lineno,
		frame.f_code.co_name,
		event,
		self.arg_repr(frame, event, arg),
		self.locals_repr(frame, event, arg)))

	def arg_repr(self, frame, event, arg):
		my_repr = None
		if "return" == event:
			my_repr = repr(arg)
			if len(my_repr) > self.max_repr_length:
				my_repr = "'omitted'"
			return "value=%s " % my_repr
		elif "exception" == event:
			my_repr = repr(arg[1])
			if len(my_repr) > self.max_repr_length:
				my_repr = "'omitted'"
			return "type=%s value=%s " % (arg[0], my_repr)

		return ""

	def trace_line(self, frame, event, arg):
		writemsg("%s line=%d\n" % (self.trim_filename(frame.f_code.co_filename), frame.f_lineno))

	def ignore_filename(self, filename):
		if filename:
			for x in self.ignore_prefixes:
				if filename.startswith(x):
					return True
		return False

	def locals_repr(self, frame, event, arg):
		"""Create a representation of the locals dict that is suitable for
		tracing output."""

		my_locals = frame.f_locals.copy()

		# prevent unsafe  __repr__ call on self when __init__ is called
		# (method calls aren't safe until after __init__  has completed).
		if frame.f_code.co_name == "__init__" and "self" in my_locals:
			my_locals["self"] = "omitted"

		# We omit items that will lead to unreasonable bloat of the trace
		# output (and resulting log file).
		for k, v in my_locals.iteritems():
			my_repr = repr(v)
			if len(my_repr) > self.max_repr_length:
				my_locals[k] = "omitted"
		return my_locals

class prefix_trimmer(object):
	def __init__(self, prefix):
		self.prefix = prefix
		self.cut_index = len(prefix)
		self.previous = None
		self.previous_trimmed = None

	def trim(self, s):
		"""Remove a prefix from the string and return the result.
		The previous result is automatically cached."""
		if s == self.previous:
			return self.previous_trimmed
		else:
			if s.startswith(self.prefix):
				self.previous_trimmed = s[self.cut_index:]
			else:
				self.previous_trimmed = s
			return self.previous_trimmed
