/* sbt -- Simple Build Tool
 * Copyright 2008 Mark Harrah */

package sbt

import org.scalacheck._
import Prop._

import scala.collection.mutable.HashSet

object DagSpecification extends Properties("Dag")
{
	property("No repeated nodes") = forAll{ (dag: TestDag) => isSet(dag.topologicalSort) }
	property("Sort contains node") = forAll{ (dag: TestDag) => dag.topologicalSort.contains(dag) }
	property("Dependencies precede node") = forAll{ (dag: TestDag) => dependenciesPrecedeNodes(dag.topologicalSort) }

	implicit lazy val arbTestDag: Arbitrary[TestDag] = Arbitrary(Gen.sized(dagGen))
	private def dagGen(nodeCount: Int): Gen[TestDag] =
	{
		val nodes = new HashSet[TestDag]
		def nonterminalGen(p: Gen.Params): Gen[TestDag] =
		{
			for(i <- 0 until nodeCount; nextDeps <- Gen.someOf(nodes).apply(p))
				nodes += new TestDag(i, nextDeps)
			for(nextDeps <- Gen.someOf(nodes)) yield
				new TestDag(nodeCount, nextDeps)
		}
		Gen.parameterized(nonterminalGen)
	}
	
	private def isSet[T](c: Seq[T]) = Set(c: _*).size == c.size
	private def dependenciesPrecedeNodes(sort: List[TestDag]) =
	{
		val seen = new HashSet[TestDag]
		def iterate(remaining: List[TestDag]): Boolean =
		{
			remaining match
			{
				case Nil => true
				case node :: tail =>
					if(node.dependencies.forall(seen.contains) && !seen.contains(node))
					{
						seen += node
						iterate(tail)
					}
					else
						false
			}
		}
		iterate(sort)
	}
}
class TestDag(id: Int, val dependencies: Iterable[TestDag]) extends Dag[TestDag]
{
	override def toString = id + "->" + dependencies.mkString("[", ",", "]")
}