package play.jobs

import scala.actors._

import play._
import play.exceptions._



object Asyncs {
  //TODO:maybe it needs to be reimplemented to avoid using casting, but the interface is OK
  def awaitForAll[A](timeout: Long, futures: Seq[Future[A]]): Seq[Option[A]] = Futures.awaitAll(timeout, futures: _*).map(_.asInstanceOf[Option[A]])
}

/**
 * provides actor support for play, this can be used as a replacement for jobs
 */
trait PlayActor extends Actor {
  /**
   *  @param msg the message being sent
   *  @return  Future task
   */
  def !!![T](msg: Function0[T]): Future[Either[Throwable, T]] = (PlayActor !! msg).asInstanceOf[Future[Either[Throwable, T]]]

  /**
   * actor reactor loop
   */
  def act {
    loop{
      react{
        case f: Function0[_] => play.Invoker.invokeInThread(new play.Invoker.DirectInvocation() {
          override def execute {
            try {
              sender ! Right(f())
            } catch {
              case e => val element = PlayException.getInterestingStrackTraceElement(e)
              if (element != null) {
                error(
                  new JavaExecutionException(
                    Play.classes.getApplicationClass(element.getClassName()), element.getLineNumber(), e
                  )

                  ,
                  "Caught in PlayActor"
                )
              } else {
                error(e, "Caught in PlayActor")
              }
              sender ! Left(e)
            }
          }
        })
        case _ => sender ! Left(new Exception("Unsupported message type"))
      }
    }
  }

  start
}

object PlayActor extends PlayActor

