package wow.doge.mygame.executors

import akka.dispatch.{
  DispatcherPrerequisites,
  ExecutorServiceFactory,
  ExecutorServiceConfigurator
}
import com.typesafe.config.Config
import java.util.concurrent.{
  ExecutorService,
  AbstractExecutorService,
  ThreadFactory,
  TimeUnit
}
import java.util.Collections
import javax.swing.SwingUtilities
import javafx.application.Platform
import monix.execution.Scheduler
import scala.concurrent.ExecutionContext
import java.util.concurrent.Executor
import wow.doge.mygame.Main

// First we wrap invokeLater/runLater as an ExecutorService
trait GUIExecutorService extends AbstractExecutorService {
  def execute(command: Runnable): Unit

  def shutdown(): Unit = ()

  def shutdownNow() = Collections.emptyList[Runnable]

  def isShutdown = false

  def isTerminated = false

  def awaitTermination(l: Long, timeUnit: TimeUnit) = true
}

object JavaFXExecutorService extends GUIExecutorService {
  override def execute(command: Runnable) = Platform.runLater(command)
}

object SwingExecutorService extends GUIExecutorService {
  override def execute(command: Runnable) = SwingUtilities.invokeLater(command)
}

object JMEExecutorService extends GUIExecutorService {
  override def execute(command: Runnable) = Main.gameApp.enqueue(command)
}

class JavaFXEventThreadExecutorServiceConfigurator(
    config: Config,
    prerequisites: DispatcherPrerequisites
) extends ExecutorServiceConfigurator(config, prerequisites) {
  private val f = new ExecutorServiceFactory {
    def createExecutorService: ExecutorService = JavaFXExecutorService
  }

  def createExecutorServiceFactory(
      id: String,
      threadFactory: ThreadFactory
  ): ExecutorServiceFactory = f
}

class JMEThreadExecutorServiceConfigurator(
    config: Config,
    prerequisites: DispatcherPrerequisites
) extends ExecutorServiceConfigurator(config, prerequisites) {
  private val f = new ExecutorServiceFactory {
    def createExecutorService: ExecutorService = JMEExecutorService
  }

  def createExecutorServiceFactory(
      id: String,
      threadFactory: ThreadFactory
  ): ExecutorServiceFactory = f
}

// Then we create an ExecutorServiceConfigurator so that Akka can use our SwingExecutorService for the dispatchers
class SwingEventThreadExecutorServiceConfigurator(
    config: Config,
    prerequisites: DispatcherPrerequisites
) extends ExecutorServiceConfigurator(config, prerequisites) {
  private val f = new ExecutorServiceFactory {
    def createExecutorService: ExecutorService = SwingExecutorService
  }

  def createExecutorServiceFactory(
      id: String,
      threadFactory: ThreadFactory
  ): ExecutorServiceFactory = f
}

object JFXExecutionContexts {
  val javaFxExecutionContext: ExecutionContext =
    ExecutionContext.fromExecutor(new Executor {
      def execute(command: Runnable): Unit = {
        Platform.runLater(command)
      }
    })
  val fxScheduler =
    Scheduler(javaFxExecutionContext)

}
