package sbt.complete

	import DefaultParsers._
	import TypeString._

/** Basic representation of types parsed from Manifest.toString.
* This can only represent the structure of parameterized types.
* All other types are represented by a TypeString with an empty `args`. */
private[sbt] final class TypeString(val base: String, val args: List[TypeString])
{
	override def toString =
		if(base.startsWith(FunctionName))
			args.dropRight(1).mkString("(", ",", ")") + " => " + args.last
		else if(base.startsWith(TupleName))
			args.mkString("(",",",")")
		else
			cleanupTypeName(base) + (if(args.isEmpty) "" else args.mkString("[", ",", "]"))
}

private[sbt] object TypeString
{
	/** Makes the string representation of a type as returned by Manifest.toString more readable.*/
	def cleanup(typeString: String): String =
		parse(typeString, typeStringParser) match {
			case Right(ts) => ts.toString
			case Left(err) => typeString
		}

	/** Makes a fully qualified type name provided by Manifest.toString more readable.
	* The argument should be just a name (like scala.Tuple2) and not a full type (like scala.Tuple2[Int,Boolean])*/
	def cleanupTypeName(base: String): String =
		dropPrefix(base).replace('$', '.')

	/** Removes prefixes from a fully qualified type name that are unnecessary in the presence of standard imports for an sbt setting. 
	* This does not use the compiler and is therefore a conservative approximation.*/
	def dropPrefix(base: String): String =
		if(base.startsWith(SbtPrefix))
			base.substring(SbtPrefix.length)
		else if(base.startsWith(CollectionPrefix))
		{
			val simple = base.substring(CollectionPrefix.length)
			if(ShortenCollection(simple)) simple else base
		}
		else if(base.startsWith(ScalaPrefix))
			base.substring(ScalaPrefix.length)
		else if(base.startsWith(JavaPrefix))
			base.substring(JavaPrefix.length)
		else
			TypeMap.getOrElse(base, base)

	final val CollectionPrefix = "scala.collection."
	final val FunctionName = "scala.Function"
	final val TupleName = "scala.Tuple"
	final val SbtPrefix = "sbt."
	final val ScalaPrefix = "scala."
	final val JavaPrefix = "java.lang."
	/* scala.collection.X -> X */
	val ShortenCollection = Set("Seq", "List", "Set", "Map", "Iterable")
	val TypeMap = Map(
		"java.io.File" -> "File",
		"java.net.URL" -> "URL",
		"java.net.URI" -> "URI"
	)

	/** A Parser that extracts basic structure from the string representation of a type from Manifest.toString.
	* This is rudimentary and essentially only decomposes the string into names and arguments for parameterized types.
	* */
	lazy val typeStringParser: Parser[TypeString] =
	{
		def isFullScalaIDChar(c: Char) = isScalaIDChar(c) || c == '.' || c == '$'
		lazy val fullScalaID = identifier(IDStart, charClass(isFullScalaIDChar, "Scala identifier character") )
		lazy val tpe: Parser[TypeString] =
			for( id <- fullScalaID; args <- ('[' ~> rep1sep(tpe, ',') <~ ']').?) yield
				 new TypeString(id, args.toList.flatten)
		tpe
	}
}