# Copyright 1999-2009 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

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.items():
			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
