package com.airlock.iam.base.misc.exception;

import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.Function;
import org.apache.commons.lang3.exception.ExceptionUtils;

public final class Exceptions {
   public static boolean isOrHasCause(Throwable e, Class<? extends Throwable> cause) {
      return ExceptionUtils.indexOfThrowable(e, cause) >= 0;
   }

   public static <T> T wrapException(Callable<T> callable, Function<Exception, ? extends RuntimeException> exceptionMapper) {
      try {
         return callable.call();
      } catch (Exception e) {
         throw (RuntimeException)exceptionMapper.apply(e);
      }
   }

   public static void wrapException(Exceptions.Executable executable, Function<Exception, ? extends RuntimeException> exceptionMapper) {
      try {
         executable.execute();
      } catch (Exception e) {
         throw (RuntimeException)exceptionMapper.apply(e);
      }
   }

   public static <T> T assertNoException(Callable<T> callable) {
      try {
         return callable.call();
      } catch (Exception e) {
         throw new AssertionError(e);
      }
   }

   public static <T extends Throwable> Optional<T> findCause(Throwable e, Class<T> cause) {
      int index = ExceptionUtils.indexOfThrowable(e, cause);
      return index < 0 ? Optional.empty() : Optional.of((T)ExceptionUtils.getThrowableList(e).get(index));
   }

   private Exceptions() {
      throw new AssertionError();
   }

   @FunctionalInterface
   public interface Executable {
      void execute() throws Exception;
   }
}
