package sbt.inc

// stolen from Josh
object StronglyConnected
{
	def apply[N](nodes: Iterable[N])(dependencies: N => Iterable[N]): Set[Set[N]] =
	{
		val stack = new collection.mutable.Stack[N]
		val onStack = new collection.mutable.HashSet[N]
		val scc = new collection.mutable.ArrayBuffer[Set[N]]
		val index = new collection.mutable.ArrayBuffer[N]
		val lowLink = new collection.mutable.HashMap[N, Int]
	  
		def tarjanImpl(v: N)
		{
			index += v
			lowLink(v) = index.size-1
			stack.push(v)
			onStack += v
			for(n <- dependencies(v))
			{
				if( !index.contains(n) )
				{
					tarjanImpl(n)
					lowLink(v) = math.min(lowLink(v), lowLink(n))
				}
				else if(onStack(n))
					lowLink(v) = math.min(lowLink(v), index.indexOf(n))
			}

			if(lowLink(v) == index.indexOf(v))
			{
				val components = new collection.mutable.ArrayBuffer[N]
				def popLoop()
				{
					val popped = stack.pop()
					onStack -= popped
					components.append(popped)
					if(popped != v) popLoop()
				}
				popLoop()
				scc.append(components.toSet)
			}
		}

		for(node <- nodes)
			if( !index.contains(node) )
				tarjanImpl(node)
		scc.toSet
	}
}