package ru.dbotthepony.kstarbound.util

import java.util.concurrent.Callable
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionStage
import java.util.concurrent.Delayed
import java.util.concurrent.ExecutorService
import java.util.concurrent.Future
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit

class ExecutorWithScheduler(val executor: ExecutorService, val scheduler: ScheduledExecutorService) : ExecutorService by executor, ScheduledExecutorService {
	override fun schedule(command: Runnable, delay: Long, unit: TimeUnit): ScheduledFuture<*> {
		return scheduler.schedule(Runnable {
			executor.submit(command)
		}, delay, unit)
	}

	private class Proxy<T>(val future: CompletableFuture<T>, val parent: ScheduledFuture<*>) : Future<T> by future, ScheduledFuture<T> {
		override fun compareTo(other: Delayed?): Int {
			return parent.compareTo(other)
		}

		override fun getDelay(unit: TimeUnit): Long {
			return parent.getDelay(unit)
		}
	}

	// won't react to cancels... man.
	override fun <V : Any?> schedule(callable: Callable<V>, delay: Long, unit: TimeUnit): ScheduledFuture<V> {
		val future = CompletableFuture<CompletionStage<V>>()
		val scheduled = scheduler.schedule(Callable { future.complete(CompletableFuture.supplyAsync(callable::call, executor)) }, delay, unit)
		return Proxy(future.thenCompose { it }, scheduled)
	}

	override fun scheduleAtFixedRate(
		command: Runnable,
		initialDelay: Long,
		period: Long,
		unit: TimeUnit
	): ScheduledFuture<*> {
		return scheduler.scheduleAtFixedRate(Runnable {
			executor.submit(command)
		}, initialDelay, period, unit)
	}

	override fun scheduleWithFixedDelay(
		command: Runnable,
		initialDelay: Long,
		delay: Long,
		unit: TimeUnit
	): ScheduledFuture<*> {
		return scheduler.scheduleWithFixedDelay(Runnable {
			executor.submit(command)
		}, initialDelay, delay, unit)
	}
}