/*
   Copyright 2010 Aaron J. Radke

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
package cc.drx

 //note: the cc.drx.ScheduledContext is used here instead the aliased java.util.concurrent.ScheduledThreadPoolExecutor to provide a more drx focused implicit not found message provided in the cc.drx package object
import cc.drx.{ScheduledContext => SC} //using this alias for schedule executor provides better missing implicit warning messagse than the one for java
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit.NANOSECONDS
import scala.concurrent.Promise

//TODO replace the sleeping loops in cc.drx.Time with this schedule based delays from the Repeater

//--schedulers
// import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
//https://docs.scala-lang.org/overviews/core/futures.html
//maybe something like the following:
//https://stackoverflow.com/a/37737385/622016  (uses scheduled exec Implicit.sc)
//https://stackoverflow.com/a/16363444/622016 (uses java.util.Timer tasks

/* TODO implement with a java timer so the scheduler is not required https://stackoverflow.com/a/16363444/622016 (uses java.util.Timer tasks
def delayTimer[A](f: => A)(implicit ex:ExecutionContext):Future[A] = {
  mkPromise{p => 
   ex.schedule(Java.Runnable(p complete Try(f)), ns.toLong, NANOSECONDS) 
  }
}
*/

/**a cancelable and scheduler based around drx.Time*/
object Repeater{
  private def mkPromise[A](f: Promise[A] => _):Future[A] = {val p = Promise[A](); f(p); p.future}

  def delay[A](t:Time, f: => A)(implicit ex:SC):Future[A] =
    mkPromise{p => ex.schedule(Java.Runnable(p complete Try(f)), t.ns.toLong, NANOSECONDS) }
  def repeat(dt:Time, tEnd:Option[Time], f: => Unit)(implicit ex:SC) = new Repeater(
    ex.scheduleAtFixedRate(Java.Runnable(f), 0L, dt.ns.toLong, NANOSECONDS),
    tEnd
  )
  def repeatSpaced(dt:Time, tEnd:Option[Time], f: => Unit)(implicit ex:SC) = new Repeater(
    ex.scheduleWithFixedDelay(Java.Runnable(f), 0L, dt.ns.toLong, NANOSECONDS),
    tEnd
  )
}
class Repeater[A]( sf: ScheduledFuture[A], timeout:Option[Time]=None)(implicit ex:SC){
  //TODO add built in counters
  // private val t0 = System.nanoTime
  timeout.foreach{_ delay stop}  //if timout exits use the time.delay to schedule a stop
  def stop:Unit = {sf.cancel(true); ()}
}