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

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

import javax.inject.Inject;

import de.ivu.elect.jee.exchange.Violations;
import de.ivu.elect.business.gebietsbaum.boundary.GebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietTK;
import de.ivu.elect.business.gruppe.boundary.GruppeDAO;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.GruppeTK;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietDAO;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;

public class GruppeImGebietEinzelbewerberValidator {

  @Inject
  transient GebietDAO gebietDAO;

  @Inject
  transient GruppeDAO gruppeDAO;

  @Inject
  transient GruppeImGebietDAO gruppeImGebietDAO;

  @Inject
  transient GebietNummerFormatter gebietNummerFormatter;

  public void pruefeEinzelbewerberAufKeinemAnderemWahlkreisInDB(List<GruppeImGebiet> gruppenInGebieten, Wahl wahl,
      Violations violations) {

    Map<GebietTK, Gebiet> gebieteNachTKMap = getGebieteNachTKMap(wahl);
    Map<GruppeTK, Gruppe> gruppeNachTKMap = getGruppeNachTKMap(wahl);

    for (GruppeImGebiet gruppeImGebiet : gruppenInGebieten) {
      Gruppe gruppeInDB = gruppeNachTKMap.get(gruppeImGebiet.getGruppe().getGruppeTK());
      if (gruppeInDB != null && gruppeInDB.isEinzelbewerber()
          && isDirektwahlgebiet(gruppeImGebiet.getGebiet().getGebietTK(), gebieteNachTKMap)) {
        List<GruppeImGebiet> vorhandeneGruppeImGebiet = gruppeImGebietDAO.findByWahlAndGruppe(wahl, gruppeInDB);
        for (GruppeImGebiet gruppeImGebietVorhanden : vorhandeneGruppeImGebiet) {
          if (gruppeImGebietVorhanden.getGebiet().isDirektwahlgebiet()
              && !gruppeImGebietVorhanden.getGebiet().getGebietTK().equals(gruppeImGebiet.getGebiet().getGebietTK())) {
            violations.add(new EinzelbewerberAufAnderemGebietVorhandenViolation(gruppeImGebiet.getGruppe()
                .getGruppeTK(), gebietNummerFormatter.getNummer(gruppeImGebiet.getGebiet()), gebietNummerFormatter
                .getNummer(gruppeImGebietVorhanden.getGebiet())));
          }
        }
      }
    }
  }

  public void pruefeEinzelbewerberNurAufEinemWahlkreis(List<GruppeImGebiet> gruppenInGebieten, Wahl wahl,
      Violations violations) {
    Map<GebietTK, Gebiet> gebieteNachTKMap = getGebieteNachTKMap(wahl);
    Set<GruppeTK> einzelbewerber = new HashSet<>();
    for (GruppeImGebiet gruppeImGebiet : gruppenInGebieten) {
      if (gruppeImGebiet.isEinzelbewerber()
          && isDirektwahlgebiet(gruppeImGebiet.getGebiet().getGebietTK(), gebieteNachTKMap)) {
        GruppeTK gruppeTK = gruppeImGebiet.getGruppe().getGruppeTK();
        if (!einzelbewerber.add(gruppeTK)) {
          violations.add(new EinzelbewerberTrittDoppeltAnViolation(gruppeTK));
        }
      }
    }
  }

  private Map<GebietTK, Gebiet> getGebieteNachTKMap(Wahl wahl) {
    List<Gebiet> alleGebiete = gebietDAO.findByWahl(wahl);
    return GebietTK.mappeGebietNachTK(alleGebiete);
  }

  private Map<GruppeTK, Gruppe> getGruppeNachTKMap(Wahl wahl) {
    List<Gruppe> alleGruppen = gruppeDAO.findByWahl(wahl);
    return GruppeTK.mappeGruppeNachTK(alleGruppen);
  }

  private boolean isDirektwahlgebiet(GebietTK gebietTK, Map<GebietTK, Gebiet> gebieteNachTKMap) {
    Gebiet gebiet = gebieteNachTKMap.get(gebietTK);
    return gebiet != null && gebiet.isDirektwahlgebiet();
  }
}
