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

import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import javax.ejb.Asynchronous;
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.mandant.entity.MandantPK;
import de.ivu.elect.business.wahl.entity.WahlPK;

@Singleton
@TransactionManagement(TransactionManagementType.BEAN) // keine Transaction
public class WahlMandantenAufteilenAsynchron {

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

  public static AtomicBoolean WAHLEN_AUFTEILEN_LAEUFT = new AtomicBoolean(false);

  public static AtomicBoolean WAHLEN_LOESCHEN_LAEUFT = new AtomicBoolean(false);

  @Inject
  private transient WahlMandantenAufteilenStatusErmittler wahlMandantenAufteilenStatusErmittler;

  @Inject
  private transient WahlMandantenAufteilenSynchron wahlMandantenAufteilenSynchron;

  @Asynchronous
  public void aufteilen(WahlPK wahlPK) {
    LOG.info("Wahl asynchron aufteilen: " + wahlPK);
    try {
      WAHLEN_AUFTEILEN_LAEUFT.set(true);
      boolean repeat = true;
      while (repeat) {
        Set<MandantPK> aufzuteilendeMandanten = wahlMandantenAufteilenStatusErmittler.bestimmeAufzuteilendeMandanten(wahlPK);
        if (aufzuteilendeMandanten.isEmpty()) {
          LOG.info("Fertig");
          repeat = false;
        } else {
          repeat = true;
          Set<MandantPK> dieseRunde = aufzuteilendeMandanten.stream().limit(wahlMandantenAufteilenSynchron.bestimmeAnzahlMandantenProTransaktion())
              .collect(Collectors.toSet());
          LOG.info("Teile auf: " + dieseRunde);
          wahlMandantenAufteilenSynchron.aufteilen(wahlPK, dieseRunde);
        }
      }

    } catch (Exception e) {
      LOG.warn("Fehler beim Aufteilen der Wahl: " + wahlPK + ", " + e.getMessage(), e);
    } finally {
      WAHLEN_AUFTEILEN_LAEUFT.set(false);
    }
    LOG.info("Wahl asynchron aufteilen: " + wahlPK + " - done");
  }

  @Asynchronous
  public void aufgeteilteWahlenLoeschen(WahlPK wahlPK) {
    LOG.info("Wahl asynchron löschen: " + wahlPK);
    try  {
      WAHLEN_LOESCHEN_LAEUFT.set(true);
      boolean repeat = true;
      while (repeat) {
        Set<MandantPK> zuLoeschendeMandanten = wahlMandantenAufteilenStatusErmittler.bestimmeZuLoeschendeMandanten(wahlPK);
        if (zuLoeschendeMandanten.isEmpty()) {
          LOG.info("Fertig");
          repeat = false;
        } else {
          repeat = true;
          Set<MandantPK> dieseRunde = zuLoeschendeMandanten.stream().limit(1).collect(Collectors.toSet());
          LOG.info("Lösche auf: " + dieseRunde);
          wahlMandantenAufteilenSynchron.loeschen(wahlPK, dieseRunde);
        }
      }
    } catch (Exception e) {
      LOG.warn("Fehler beim Löschen der aufgeteilten Wahlen für Wahl: " + wahlPK + ", " + e.getMessage(), e);
    } finally {
      WAHLEN_LOESCHEN_LAEUFT.set(false);
    }

    LOG.info("Wahl asynchron löschen: " + wahlPK + " - done");
  }

}
