
package de.ivu.elect.jee.exception;

import javax.ejb.ApplicationException;
import javax.faces.context.FacesContext;

import org.slf4j.Logger;

import de.ivu.elect.jee.cdi.BeanManagerUtil;
import de.ivu.elect.jee.faces.FacesContextUtil;
import de.ivu.elect.jee.faces.FacesMessageUtil;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.presentation.security.StartViewResolver;

@ApplicationException(rollback = true)
public class ElectCommonException extends RuntimeException {

  private static final long serialVersionUID = 1L;
  private final String messageKey;
  private final Object[] objects;
  private final RedirectDestination redirectDestination;
  private final LogLevel logLevel;

  public ElectCommonException(String messageKey, Throwable cause, Object... objects) {
    this(RedirectDestination.NONE, messageKey, cause, objects);
  }

  public ElectCommonException(String messageKey, Object... objects) {
    this(RedirectDestination.NONE, messageKey, objects);
  }

  public ElectCommonException(RedirectDestination redirectDestination, String messageKey, Throwable cause, Object... objects) {
    this(redirectDestination, LogLevel.ALL, messageKey, cause, objects);
  }

  public ElectCommonException(RedirectDestination redirectDestination, LogLevel logLevel, String messageKey, Throwable cause, Object... objects) {
    super(createDefaultMessage(messageKey, objects), cause);
    this.logLevel = logLevel;
    this.messageKey = messageKey;
    this.objects = objects;
    this.redirectDestination = redirectDestination;
  }

  public ElectCommonException(RedirectDestination redirectDestination, String messageKey, Object... objects) {
    this(redirectDestination, LogLevel.ALL, messageKey, objects);
  }

  public ElectCommonException(RedirectDestination redirectDestination, LogLevel logLevel, String messageKey, Object... objects) {
    super(createDefaultMessage(messageKey, objects));
    this.logLevel = logLevel;
    this.messageKey = messageKey;
    this.objects = objects;
    this.redirectDestination = redirectDestination;
  }

  public static String createDefaultMessage(String messageKey, Object[] objects) {
    StringBuilder builder = new StringBuilder(messageKey);
    if (objects != null) {
      for (int i = 0; i < objects.length; i++) {
        builder.append(" - $");
        builder.append(i);
        builder.append("='");
        builder.append(objects[i]);
        builder.append("'");
      }
    }
    return builder.toString();
  }

  public String getMessageKey() {
    return messageKey;
  }

  public Object[] getObjects() {
    return objects;
  }

  public RedirectDestination getRedirectDestination() {
    return redirectDestination;
  }

  @Override
  public String getLocalizedMessage() {
      try {
        return getLocalizedMessageFromResources(getMessageKey(), getObjects());
      } catch (Exception ise) {
        // Innerhalb von Integrationstests scheint keine Lokalisierung möglich, es kommt die Fehlermeldung:
        // Schwerwiegend: Die Anwendung wurde bei Systemstart nicht einwandfrei initialisiert, Factory konnte nicht gefunden werden: javax.faces.application.ApplicationFactory. Rügriff versucht.

        // Im Zweifelsfall default-Implementierung...
        return super.getLocalizedMessage();
    }
  }

  public LogLevel getLogLevel() {
    return logLevel;
  }

  protected static String getLocalizedMessageFromResources(String msgKey, Object... params) {
    return BeanManagerUtil.getBeanByClass(Messages.class).getMessageForMessageKey(msgKey, params);
  }

  public enum RedirectDestination {
    NONE {
      @Override
      public void redirect() {
        // nichts zu tun
      }
    },
    ERROR_VIEW {
      @Override
      public void redirect() {
        FacesContextUtil.redirectToErrorView();
      }
    },
    LOGIN_VIEW {
      @Override
      public void redirect() {
        FacesMessageUtil.addInfoMessage(FacesContext.getCurrentInstance(), "message.anmeldung.notwendig", "");
        FacesContextUtil.redirectToLoginView();
        FacesContextUtil.renderResponse();
      }
    },
    START_VIEW {
      @Override
      public void redirect() {
        FacesContextUtil.redirectToView(BeanManagerUtil.getBeanByClass(StartViewResolver.class).getStartViewId());
      }
    };

    public abstract void redirect();
  }

  public enum LogLevel {
    ALL {
      @Override
      public void log(Logger log, ElectCommonException e) {
        log.warn(e.getMessage(), e);
      }
    },
    MESSAGE_ONLY {
      @Override
      public void log(Logger log, ElectCommonException e) {
        log.warn(e.getMessage());
      }
    },
    NONE {
      @Override
      public void log(Logger log, ElectCommonException e) {
        // nichts zu tun
      }
    };

    public abstract void log(Logger log, ElectCommonException e) ;
  }

  public boolean isSecurityException(){
    return false;
  }

}
