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

import java.util.Set;
import java.util.function.BiConsumer;

import javax.ejb.Stateless;
import javax.enterprise.inject.Instance;
import javax.inject.Inject;

import de.ivu.elect.business.wahl.control.WahlterminCopyEntityExecutor;
import de.ivu.elect.business.wahl.control.WahlterminCreate;
import de.ivu.elect.business.wahl.entity.Wahltermin;
import de.ivu.elect.business.wahl.entity.WahlterminCopyEntity;

@Stateless
public class WahlterminCopyCreate {

  @Inject
  private transient Instance<WahlterminCopyEntityExecutor> executors;

  @Inject
  private transient WahlterminDAO wahlterminDao;

  @Inject
  private transient WahlterminCreate wahlterminCreate;

  public Wahltermin createWahlterminCopy(Wahltermin urspruenglichNotAttached, Wahltermin copyWahltermin, Set<WahlterminCopyEntity> auswahlZuKopieren) {
    Wahltermin wahlterminUrspruenglich = wahlterminDao.attach(urspruenglichNotAttached);
    copyWahltermin.setMandant(wahlterminUrspruenglich.getMandant());
    saveWahltermin(copyWahltermin);

    wahlterminDao.flush();
    postSaveWahltermin(copyWahltermin);

    wahlterminDao.flush();

    kopiereEntitaetenAllesFuerStichwahl(wahlterminUrspruenglich, copyWahltermin, auswahlZuKopieren);
    return copyWahltermin;

  }

  private void kopiereEntitaetenAllesFuerStichwahl(Wahltermin wahlterminUrspruenglich, Wahltermin copyWahltermin, Set<WahlterminCopyEntity> auswahlZuKopieren) {
    auswahlZuKopieren.stream().sorted().forEach(
        entity -> getWahlterminVonNachConsumer(entity).accept(wahlterminUrspruenglich, copyWahltermin));
  }

  private BiConsumer<Wahltermin, Wahltermin> getWahlterminVonNachConsumer(WahlterminCopyEntity entity) {
    for (WahlterminCopyEntityExecutor executor : executors) {
      if (entity.equals(executor.getWahlterminCopyEntity())) {
        return executor::copy;
      }
    }

    return (u, v) -> {
      throw new UnsupportedOperationException("Art nicht unterstützt: " + entity);
    };
  }

  protected void postSaveWahltermin(Wahltermin copyWahltermin) {
    // nichts zu tun
  }

  protected void saveWahltermin(Wahltermin copyWahltermin) {
    wahlterminCreate.save(copyWahltermin);
  }

}
