package de.ivu.elect.jee.performance;

import java.io.Serializable;

import javax.annotation.Priority;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Priority(1) // ELECT-15185 enabled by default
@Interceptor
@PerformanceLog(viewType = ViewType.INTERFACE/*irrelevant*/, transactionHandling = PerformanceLogTransactionHandling.AFTER_TRANSACTION/*irrelevant*/)
public class PerformanceLogInterceptor implements Serializable {

  private static final Logger LOG = LoggerFactory.getLogger(PerformanceLogInterceptor.class);

  private static final long serialVersionUID = 1L;

  @Inject
  private transient Event<PerformanceLogEvent> event;

  @AroundInvoke
  public Object secure(InvocationContext ctx) throws Exception {
    long start = System.currentTimeMillis();

    Object result;
    boolean exception = false;
    try {
      result = ctx.proceed();
    } catch (Exception e) {
      exception = true;
      throw e;
    } finally {
      try {
        if (PerformanceStore.isStatistikAktiviert()) {
          PerformanceNoLog performanceNoLog = ctx.getMethod().getAnnotation(PerformanceNoLog.class);
          // Falls vorhanden, keine Statistik loggen
          if (performanceNoLog == null) {

            // Annotation an Methode...
            PerformanceLog performanceLog = ctx.getMethod().getAnnotation(PerformanceLog.class);

            if (performanceLog == null) {
              // Fallback auf Annotation an Klasse
              performanceLog = ctx.getTarget().getClass().getAnnotation(PerformanceLog.class);
            }

            String name = ctx.getMethod().getDeclaringClass().getSimpleName() + ":" + ctx.getMethod().getName();
            if (exception) {
              name += "_EXCEPTION";
            }
            ViewAccessTarget target = new ViewAccessTarget(performanceLog.viewType(), ViewAccessType.GESAMT, PhaseIdEnum.INVOKE_APPLICATION, ViewAccessTarget.SESSION_ID_OHNE, name);

            if (performanceLog.transactionHandling().isAfterTransaction()) {
              event.fire(new PerformanceLogEvent(target, start));
            } else {
              PerformanceStore.addDuration(target, System.currentTimeMillis() - start);
            }
          }
        }
      } catch (Exception e) {
        LOG.warn("Fehler beim Loggen der Performance-Statistiken: " + e.getMessage() + ", " + ctx.getMethod());
      }
    }

    return result;
  }

}

