package jp.sf.amateras.mirage.scala

/**
 * Provides utility methods used by mirage-scala.
 */
object Utilities {

  /**
   * Runs the fiven function with the Closeable.
   * The Closeable is closed certainly after the execution of the function.
   */
  def using[A, B <: {def close(): Unit}] (closeable: B) (f: B => A): A =
    try {
      f(closeable)
    } finally {
      if(closeable != null){
        withoutException { closeable.close() }
      }
    }

  /**
   * Runs the given function without any exceptions and returns the return value of the function.
   * If any exceptions are occured, this method returns null.
   */
  def withoutExceptionOrNull[A, A1 >: A](func: => A)(implicit ev: Null <:< A1): A1 = {
    try {
      func
    } catch {
      case ex: Exception => null
    }
  }

  /**
   * Runs the given function without any exceptions and returns the return value of the function as Some(value).
   * If any exceptions are occured, this method returns None.
   */
  def withoutException[T](func: => T): Option[T] = {
    try {
      Some(func)
    } catch {
      case ex: Exception => None
    }
  }

  /**
   * Returns the specified field value by reflection.
   */
  def getField[T](target: AnyRef, fieldName: String): T = {
    val field = target.getClass().getDeclaredField(fieldName)
    field.setAccessible(true)
    field.get(target).asInstanceOf[T]
  }

  /**
   * Invokes the specified method by reflection.
   */
  def invokeMethod[T](target: AnyRef, methodName: String, types: Array[Class[_]], params: Array[AnyRef]): T = {
    val method = target.getClass().getDeclaredMethod(methodName, types:_*)
    method.setAccessible(true)
    method.invoke(target, params:_*).asInstanceOf[T]
  }

}