package sbt {

  import org.glassfish.embeddable.{GlassFish, GlassFishRuntime, GlassFishProperties, Deployer}

  trait GlassFishPlugin extends BasicWebScalaProject {
    def glassFishPort = GlassFishRunner.DefaultPort
  
    private lazy val glassFish = new GlassFishRunner(glassFishPort, temporaryWarPath)

    lazy val glassfishRun = glassfishRunAction
    def glassfishRunAction = task {
      glassFish()
    } dependsOn(prepareWebapp) describedAs("Starts the embedded GlassFish server and serves this project as a web application.")

    lazy val glassfishStop = glassfishStopAction
    def glassfishStopAction = task {
      glassFish.stop; None
    } describedAs("Stops the embedded GlassFish server that was started with glassfish-run.")

    lazy val glassfishRestart= glassfishRestartAction
    def glassfishRestartAction = task {
      glassFish.stop; glassFish()
    } describedAs("Restarts the embedded GlassFish server that was started with glassfish-run.")

  }

  object GlassFishRunner {
    val DefaultPort = 8080
    lazy val runtime = GlassFishRuntime.bootstrap
  }

  class GlassFishRunner(val port: Int, val path: Path) extends ExitHook {
    ExitHooks.register(this)

    private var glassFish: Option[GlassFish] = None
    private var deployKey: String = _

    private lazy val glassFishProps = new GlassFishProperties {
      setPort("http-listener", port)
    }

    def name = "glassfish-shutdown"
    def runBeforeExiting() { stop }

    def apply(): Option[String] = {
      if (glassFish.isDefined)
        Some("A GlassFish instance is already running")
      else
        try {
          val gf = GlassFishRunner.runtime.newGlassFish(glassFishProps)
          gf.start
          val d = gf.getService(classOf[Deployer])
          deployKey = d.deploy(path.asFile)
          glassFish = Some(gf)
          None
        } catch {
          case e => Some("Error running GlassFish: %s".format(e.getMessage))
        }
    }

    def stop() {
      glassFish.foreach { gf =>
        val d = gf.getService(classOf[Deployer])
          d.undeploy(deployKey)
          gf.stop
          gf.dispose
      }
      glassFish = None
    }
  }
}