/* sbt -- Simple Build Tool
 * Copyright 2011 Mark Harrah
 */
package sbt

	import Keys._
	import complete.{DefaultParsers, Parser}
	import DefaultParsers._
	import Project.{ScopedKey, Setting}
	import Scope.GlobalScope

object Cross
{
	final val Switch = "++"
	final val Cross = "+"

	def switchParser(state: State): Parser[(String, String)] =
	{
		val knownVersions = crossVersions(state)
		lazy val switchArgs = token(NotSpace.examples(knownVersions : _*)) ~ (token(Space ~> matched(state.combinedParser)) ?? "")
		lazy val nextSpaced = spacedFirst(Switch)
		token(Switch ~ OptSpace) flatMap { _ => switchArgs & nextSpaced }
	}
	def spacedFirst(name: String) = opOrIDSpaced(name) ~ any.+

	lazy val switchVersion = Command.arb(requireSession(switchParser)) { case (state, (version, command)) =>
		val x = Project.extract(state)
			import x._
		println("Setting version to " + version)
		val add = (scalaVersion in GlobalScope :== version) :: (scalaHome in GlobalScope :== None) :: Nil
		val cleared = session.mergeSettings.filterNot( crossExclude )
		val newStructure = Load.reapply(add ++ cleared, structure)
		Project.setProject(session, newStructure, command :: state)
	}
	def crossExclude(s: Setting[_]): Boolean =
		s.key match {
			case ScopedKey( Scope(_, Global, Global, _), scalaHome.key | scalaVersion.key) => true
			case _ => false
		}

	def crossParser(state: State): Parser[String] =
		token(Cross <~ OptSpace) flatMap { _ => token(matched( state.combinedParser & spacedFirst(Cross) )) }

	lazy val crossBuild = Command.arb(requireSession(crossParser)) { (state, command) =>
		val x = Project.extract(state)
			import x._
		val versions = crossVersions(state)
		val current = scalaVersion in currentRef get structure.data map(Switch + " " + _) toList;
		if(versions.isEmpty) command :: state else versions.map(Switch + " " + _ + " " + command) ::: current ::: state
	}
	def crossVersions(state: State): Seq[String] =
	{
		val x = Project.extract(state)
			import x._
		crossScalaVersions in currentRef get structure.data getOrElse Nil
	}
	
	def requireSession[T](p: State => Parser[T]): State => Parser[T] = s =>
		if(s get sessionSettings isEmpty) failure("No project loaded") else p(s)

}