/* sbt -- Simple Build Tool
 * Copyright 2008, 2009 Mark Harrah
 */
package xsbt

import xsbti.Logger
import scala.tools.nsc.{GenericRunnerCommand, Interpreter, InterpreterLoop, ObjectRunner, Settings}
import scala.tools.nsc.interpreter.InteractiveReader
import scala.tools.nsc.reporters.Reporter
import scala.tools.nsc.util.ClassPath

class ConsoleInterface
{
	def commandArguments(args: Array[String], bootClasspathString: String, classpathString: String, log: Logger): Array[String] =
		MakeSettings.sync(args, bootClasspathString, classpathString, log).recreateArgs.toArray[String]

	def run(args: Array[String], bootClasspathString: String, classpathString: String, initialCommands: String, cleanupCommands: String, loader: ClassLoader, bindNames: Array[String], bindValues: Array[Any], log: Logger)
	{
		lazy val interpreterSettings = MakeSettings.sync(args.toList, log)
		val compilerSettings = MakeSettings.sync(args, bootClasspathString, classpathString, log)
		
		if(!bootClasspathString.isEmpty)
			compilerSettings.bootclasspath.value = bootClasspathString
		compilerSettings.classpath.value = classpathString
		log.info(Message("Starting scala interpreter..."))
		log.info(Message(""))
		val loop = new InterpreterLoop {
		
			override def createInterpreter() = {
			
				if(loader ne null)
				{
					in = InteractiveReader.createDefault()
					interpreter = new Interpreter(settings)
					{
						override protected def parentClassLoader = if(loader eq null) super.parentClassLoader else loader
						override protected def newCompiler(settings: Settings, reporter: Reporter) = super.newCompiler(compilerSettings, reporter)
					}
					interpreter.setContextClassLoader()
				}
				else
					super.createInterpreter()

				def bind(values: Seq[(String,Any)])
				{
					// for 2.8 compatibility
					final class Compat {
						def bindValue(id: String, value: Any) =
							interpreter.bind(id, value.asInstanceOf[AnyRef].getClass.getName, value)
					}
					implicit def compat(a: AnyRef): Compat = new Compat

					for( (id, value) <- values )
						interpreter.beQuietDuring(interpreter.bindValue(id, value))
				}

				bind(bindNames zip bindValues)
			
				if(!initialCommands.isEmpty)
					interpreter.interpret(initialCommands)
			}
			override def closeInterpreter()
			{
				if(!cleanupCommands.isEmpty)
					interpreter.interpret(cleanupCommands)
				super.closeInterpreter()
			}
		}
		loop.main(if(loader eq null) compilerSettings else interpreterSettings)
	}
}
object MakeSettings
{
	def apply(args: List[String], log: Logger) =
	{
		val command = new GenericRunnerCommand(args, message => log.error(Message(message)))
		if(command.ok)
			command.settings
		else
			throw new InterfaceCompileFailed(Array(), Array(), command.usageMsg)
	}

	def sync(args: Array[String], bootClasspathString: String, classpathString: String, log: Logger): Settings =
	{
		val compilerSettings = sync(args.toList, log)
		if(!bootClasspathString.isEmpty)
			compilerSettings.bootclasspath.value = bootClasspathString
		compilerSettings.classpath.value = classpathString
		compilerSettings
	}

	def sync(options: List[String], log: Logger) =
	{
		val settings = apply(options, log)

		// -Yrepl-sync is only in 2.9.1+
		final class Compat {
			def Yreplsync = settings.BooleanSetting("-Yrepl-sync", "For compatibility only.")
		}
		implicit def compat(s: Settings): Compat = new Compat

		settings.Yreplsync.value = true
		settings
	}
}