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

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

import de.ivu.elect.business.benutzerverwaltung.boundary.RolleEdit;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPK;
import de.ivu.elect.business.mandant.boundary.MandantExtendedDAO;
import de.ivu.elect.business.protokollierung.entity.LoeschProtokollEvent;
import de.ivu.elect.business.system.entity.CacheResetEvent;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.Wahltermin;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;

@Stateless
public class GebietEdit extends AbstractGebietEdit {

  public GebietEdit() {
    super();
  }

  @Inject
  private transient MandantExtendedDAO mandantExtendedDAO;

  @Inject
  transient CacheResetEvent cacheResetEvent;

  @Inject
  transient LoeschProtokollEvent loeschProtokollEvent;

  @Inject
  transient GebietNummerFormatter gebietNummerFormatter;

  @Inject
  private transient RolleEdit rolleEdit;

  @Override
  public void save(Gebiet entity) {

    // ELECT-7964
    if (entity.getEinsehenRolle() != null) {
      if (entity.getEinsehenRolle().isPersistent()) {
        entity.getEinsehenRolle().setMandant(mandantExtendedDAO.attach(entity.getEinsehenRolle().getMandant()));
      } else {
        entity.getEinsehenRolle().setMandant(mandantExtendedDAO.attach(entity.getMandant()));
      }
    }

    // ELECT-7964
    if (entity.getBearbeitenRolle() != null) {
      if (entity.getBearbeitenRolle().isPersistent()) {
        entity.getBearbeitenRolle().setMandant(mandantExtendedDAO.attach(entity.getBearbeitenRolle().getMandant()));
      } else {
        entity.getBearbeitenRolle().setMandant(mandantExtendedDAO.attach(entity.getMandant()));
      }
    }

    super.save(entity);

    rolleEdit.updateRolleArtFuerAlleRollen(entity.getMandant());
  }

  @Override
  public void delete(Gebiet entity) {
    Gebiet attachedEntity = getAttachedEntity(entity);
    requireDeleteMoeglich(attachedEntity);
    deleteOhnePruefung(attachedEntity);
  }

  protected void deleteOhnePruefung(Gebiet attachedEntity) {
    loeschProtokollEvent.sendeLoeschProtokollEvent(attachedEntity.getWahltermin(), attachedEntity.getWahl(), attachedEntity, "loesch.protokoll.gebiet", gebietNummerFormatter.getDarstellung(
        attachedEntity));
    attachedEntity.setUebergeordnetesGebiet(null);
    super.delete(attachedEntity);
    cacheResetEvent.sendEvent(); // ELECT-8185
  }

  protected void requireDeleteMoeglich(Gebiet attachedEntity) {
    // hier nichts zu tun
  }

  public void speichereReihenfolge(Gebiet rootGebietNotAttached, Map<GebietPK, List<GebietPK>> neueHierarchie, Set<GebietPK> gebieteZuLoeschenInTree, Map<GebietPK, Long> neuePositionen) {
    Gebiet rootGebiet = dao.attach(rootGebietNotAttached);

    Gebiet bisherigesUebergeordnetesGebiet = rootGebiet.getUebergeordnetesGebiet();

    Map<GebietPK, Gebiet> gebieteNachPk = new HashMap<>();

    for (GebietPK gebietPK : neueHierarchie.keySet()) {
      gebieteNachPk.put(gebietPK, dao.findByPrimaryKey(gebietPK));
    }
    for (List<GebietPK> gebietPKs : neueHierarchie.values()) {
      for (GebietPK gebietPK : gebietPKs) {
        gebieteNachPk.put(gebietPK, dao.findByPrimaryKey(gebietPK));
      }
    }

    for (GebietPK gebietPK : gebieteZuLoeschenInTree) {
      gebieteNachPk.put(gebietPK, dao.findByPrimaryKey(gebietPK));
    }

    for (Gebiet value : gebieteNachPk.values()) {
      value.setUebergeordnetesGebiet(null);
      value.removeAllGebiets();
    }
    dao.flush();
    for (GebietPK gebietPK : gebieteZuLoeschenInTree) {
      delete(gebieteNachPk.get(gebietPK));
      gebieteNachPk.remove(gebietPK);
    }
    dao.flush();


    for (Map.Entry<GebietPK, List<GebietPK>> entry : neueHierarchie.entrySet()) {
      Gebiet parent = gebieteNachPk.get(entry.getKey());
      setzePosition(parent, rootGebiet, neuePositionen);
      for (GebietPK gebietPK : entry.getValue()) {
        Gebiet child = gebieteNachPk.get(gebietPK);
        setzePosition(child, rootGebiet, neuePositionen);
        child.setUebergeordnetesGebiet(parent);
      }
    }

    gebieteNachPk.values().stream()
        .filter(g -> g.getUebergeordnetesGebiet() == null)
        .findFirst()
        .ifPresent(oberstesGebiet -> oberstesGebiet.setUebergeordnetesGebiet(bisherigesUebergeordnetesGebiet));

    postSpeichereReichenfolge(rootGebiet.getWahltermin(), rootGebiet.getWahl());

  }

  protected void postSpeichereReichenfolge(Wahltermin wahltermin, Wahl wahl) {
    // nichts zu tun

  }

  protected void setzePosition(Gebiet gebiet, Gebiet rootGebiet, Map<GebietPK, Long> positionen) {
    if (gebiet.equals(rootGebiet)) {
      return; // oberstes Gebiet nicht verändern
    }
    Long neuePosition = positionen.get(gebiet.getPk());
    if (neuePosition != null) {
      setzeNeuePosition(gebiet, neuePosition);
    }

  }

  protected void setzeNeuePosition(Gebiet gebiet, Long neuePosition) {
    gebiet.setPosition(neuePosition);
  }
}
