import sbt._
import org.apache.commons.lang3.SystemUtils
import org.apache.commons.lang3.StringUtils.replaceEach

/**
 * A class that generates a shell or batch script to execute a Scala program.
 */
case class ScalaTool(mainClass: String,
                     classpath: List[String],
                     properties: Map[String, String],
                     javaOpts: String,
                     toolFlags: String) {
  //  For classpath, the platform specific
  //  demarcation of any script variables (e.g. `${SCALA_HOME}` or
  //  `%SCALA_HOME%`) can be specified in a platform independent way (e.g.
  //  `@SCALA_HOME@`) and automatically translated for you.
  def patchedToolScript(template: String, forWindows: Boolean) = {
    val varRegex = """@(\w+)@""" // the group should be able to capture each of the keys of the map below
    val platformClasspath =
      if(forWindows) classpath.mkString(";").replace('/', '\\').replaceAll(varRegex, "%$1%")
      else if(SystemUtils.IS_OS_WINDOWS) {
        // When building on Windows, use a Windows classpath in the shell script (for MSYS/Cygwin).
        // This is only used for "quick", which uses absolute paths, so it is not portable anyway.
        classpath.mkString(";").replace("\\", "\\\\").replaceAll(varRegex, """\${$1}""")
      } else classpath.mkString(":").replace('\\', '/').replaceAll(varRegex, """\${$1}""")

    val variables = Map(
      "@@"           -> "@", // for backwards compatibility
      "@class@"      -> mainClass,
      "@properties@" -> (properties map { case (k, v) => s"""-D$k="$v""""} mkString " "),
      "@javaflags@"  -> javaOpts,
      "@toolflags@"  -> toolFlags,
      "@classpath@"  -> platformClasspath
    )

    val (from, to) = variables.unzip
    replaceEach(template, from.toArray, to.toArray)
  }

  def writeScript(file: String, platform: String, rootDir: File, outDir: File): File = {
    val forWindows   = platform match { case "windows" => true case _ => false }
    val templatePath = s"scala/tools/ant/templates/tool-$platform.tmpl"
    val suffix       = if(forWindows) ".bat" else ""
    val scriptFile   = outDir / s"$file$suffix"
    val patched      = patchedToolScript(IO.read(rootDir / templatePath).replace("\r", ""), forWindows)
    IO.write(scriptFile, if(forWindows) patched.replace("\n", "\r\n") else patched)
    scriptFile
  }
}
