
package de.ivu.elect.business.ergebnis.control;

import java.util.Date;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

import javax.ejb.DependsOn;
import javax.ejb.Singleton;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.inject.Inject;

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

import de.ivu.elect.business.ergebnis.boundary.ErgebnisberechnungStatistikStore;
import de.ivu.elect.business.ergebnis.entity.ErgebnisPK;
import de.ivu.elect.business.ergebnis.entity.ErgebnisberechnungStatistikEntry;
import de.ivu.elect.business.mandant.entity.MandantPK;
import de.ivu.elect.business.system.control.AbstractElectMandantBackgroundService;
import de.ivu.elect.business.system.entity.SystemLogQuelle;


import static de.ivu.elect.business.system.entity.SystemLogQuelle.ZWISCHENERGEBNISBERECHNUNG;

@Singleton
@DependsOn("DbInit")
//https://issues.jboss.org/browse/EJBTHREE-2070 (keine Transaktion)
@TransactionManagement(TransactionManagementType.BEAN)
public class ZwischenergebnisberechnungBackgroundService extends AbstractElectMandantBackgroundService {

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

  public static final AtomicLong RUNNING = createRunning();

  public static final AtomicBoolean DISABLED = createDisabled();

  @Inject
  private transient Zwischenergebnisberechnung zwischenergebnisberechnung;

  @Inject
  private transient ErgebnisberechnungStatistikStore ergebnisberechnungStatistikStore;

  @Override
  protected AtomicBoolean getDisabledInternal() {
    return DISABLED;
  }

  @Override
  protected boolean isSomethingToDoInternal(MandantPK mandantPK) {
    return zwischenergebnisberechnung.isErgebnisZuBerechnen(mandantPK);
  }

  @Override
  protected void doSomethingInternal(MandantPK mandantPK) {
    Date date = new Date();
    long start = date.getTime();
    ErgebnisPK ergebnisPK = zwischenergebnisberechnung.berechne(mandantPK);
    if (ergebnisPK != null) {
      try {
        long dauerInMs = System.currentTimeMillis() - start;
        LOG.info("Berechne Ergebnis -  fertig, Dauer: " + dauerInMs + " ms, " + ergebnisPK);
        ergebnisberechnungStatistikStore.add(ergebnisPK, new ErgebnisberechnungStatistikEntry(date, dauerInMs));
      } catch (Exception e) {
        LOG.warn("Fehler beim Schreiben der Ergebnis-Statistik: " + e.getMessage(), e);
      }
    }

  }

  @Override
  public SystemLogQuelle getSystemLogQuelle() {
    return ZWISCHENERGEBNISBERECHNUNG;
  }

  @Override
  public AtomicLong getRunning() {
    return RUNNING;
  }

  @Override
  protected boolean isRetryAfterException(Exception e) {
    return super.isRetryAfterException(e) || isConstraintViolation(e);
  }

  private boolean isConstraintViolation(Throwable e) {
    if (e == null) {
      return false;
    }

    if (e.getMessage() != null) {
      // Spezialfall ELECT-6713
      if (e.getMessage().contains("Cannot add or update a child row: a foreign key constraint fails")) {
        return true;
      }
    }

    return isConstraintViolation(e.getCause());
  }

  public static boolean isServiceRunning() {
    return RUNNING.get()>0;
  }
}
