# This file is part of TracTicketDep.
#
# TracTicketDep is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# TracTicketDep is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Author: Risto Kankkunen

"""
Copyright (c) 2008 Risto Kankkunen. All rights reserved.
"""

from mastertickets.model import TicketLinks

def ticket_parents(env, ticket):
	"""
	Generates a sequence of (depth, ticket) pairs describing ticket
	parent relationships (higher depth indicates higher ancestry)
	"""
	yield 0, ticket
	parents = TicketLinks(env, ticket).blocking
	for p in parents:
		for depth, tkt in ticket_parents(env, p):
			yield depth + 1, tkt

class ticket_children:
	def __init__(self, env, ticket, max_depth=-1):
		self.env = env
		if isinstance(ticket, (basestring, int)):
			self.tickets = ticket,
		else:
			self.tickets = tuple(ticket)
		self._max_depth = max_depth
		# do not recurse into top-level tickets (as part of ticket traversal)
		self._tickets_seen = set(self.tickets)

	def __iter__(self):
		return self._topiter()

	def _topiter(self):
		for t in self.tickets:
			# make sure we recurse from the top-level tickets
			self._tickets_seen.remove(t)
			for ev in self._iter(t, 0):
				yield ev

	def _iter(self, ticket, depth):
		yield depth, ticket

		if ticket in self._tickets_seen:
			return
		self._tickets_seen.add(ticket)

		if not depth >= self._max_depth > 0:
			for blocker in TicketLinks(self.env, ticket).blocked_by:
				for ev in self._iter(int(blocker), depth+1):
					yield ev

	def treeiter(self):
		roots = set(self.tickets)
		nodes = dict()
		
		def mktree(ticket):
			if ticket in nodes:
				return nodes[ticket]
			children = []
			for blocker in TicketLinks(self.env, ticket).blocked_by:
				blocker = int(blocker)
				roots.discard(blocker)
				children.append(mktree(blocker))
			tree = ticket, children
			nodes[ticket] = tree
			return tree

		for t in self.tickets:
			mktree(t)

		def _iter(n, depth):
			ticket, children = n
			yield depth, ticket

			if not depth >= self._max_depth > 0:
				for t in children:
					for ev in _iter(t, depth + 1):
						yield ev

		for t in roots:
			for ev in _iter(nodes[t], 0):
				yield ev
