package com.javacodegeeks.console

import xsbti.AppMain
import xsbti.AppConfiguration

import sbt.GlobalLogging
import sbt.BasicCommands
import sbt.MainLogging
import sbt.{AttributeMap, AttributeEntry}
import sbt.Command
import sbt.MainLoop
import sbt.State
import sbt.ConsoleOut
import sbt.Help
import sbt.complete.DefaultParsers._

import java.io.File
import java.io.PrintWriter
import java.net.URI

import dispatch._
import dispatch.Defaults._

import scala.concurrent.Await
import scala.concurrent.duration._
import scala.language.postfixOps
import sbt.AttributeKey

class ConsoleApp extends AppMain {
  def run(configuration: AppConfiguration) = 
    MainLoop.runLogged(initialState(configuration))
  
  val timeout = AttributeKey[Int]("timeout", "The timeout (in seconds) to wait for HTTP response")
  val logFile = File.createTempFile("console-interactive", "log")
  val console = ConsoleOut.systemOut

  def initialState(configuration: AppConfiguration): State = {
    val commandDefinitions = fetch +: BasicCommands.allBasicCommands
    val commandsToRun = "iflast shell" +: configuration.arguments.map(_.trim)
     
    State(
      configuration, 
      commandDefinitions, 
      Set.empty, 
      None, 
      commandsToRun, 
      State.newHistory,
      AttributeMap(AttributeEntry(timeout, 1)), 
      globalLogging, 
      State.Continue 
    )
  }
  
  val FetchCommand = "fetch"
  val FetchCommandHelp = s"""$FetchCommand <url>

         Fetches the <url> and prints out the response
  """
  
  lazy val url = (token(Space) ~> token(basicUri, "<url>")) <~ SpaceClass.*
  val fetch = Command(FetchCommand, Help.more(FetchCommand, FetchCommandHelp))(_ => mapOrFail(url)(_.toURL()) !!! "URL is not valid") { (state, url) =>
    val result = Await.result(Http(dispatch.url(url.toString()) OK as.String), state get timeout getOrElse 5 seconds)
    state.log.info(s"${result}")
    state
  }

  def globalLogging: GlobalLogging = 
    GlobalLogging.initial(MainLogging.globalDefault(console), logFile, console)

  class Exit(val code: Int) extends xsbti.Exit
}