package de.ivu.elect.was.exchange.wahlbeteiligung.mapper;

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

import javax.enterprise.inject.Specializes;
import javax.inject.Inject;

import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietFactory;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahlbeteiligung.entity.Wahlbeteiligung;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertungStatus;
import de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertungTyp;
import de.ivu.elect.core.exchange.wahlbeteiligung.mapper.WahlbeteiligungMapper;
import de.ivu.elect.interfaces.core.GebietReferenz;
import de.ivu.elect.interfaces.was.wahlbeteiligung.ErfassteWahlbeteiligung;
import de.ivu.elect.interfaces.was.wahlbeteiligung.WahlbeteiligungAuswertung;
import de.ivu.elect.interfaces.was.wahlbeteiligung.WahlbeteiligungAuswertungReferenz;
import de.ivu.elect.interfaces.was.wahlbeteiligung.WahlbeteiligungExchange;

@Specializes
public class WasWahlbeteiligungMapper extends WahlbeteiligungMapper {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient WahldurchfuehrungsgebietFactory wahldurchfuehrungsgebietFactory;

  public WahlbeteiligungExchange mappeAuswertungen(List<de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung> wahlbeteiligungAuswertungs) {
    WahlbeteiligungExchange result = new WahlbeteiligungExchange();

    Map<Wahldurchfuehrungsgebiet, List<Wahlbeteiligung>> wahlbeteiligungenImGebiet = new HashMap<>();

    for (de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung from : wahlbeteiligungAuswertungs) {

      WahlbeteiligungAuswertung to = new WahlbeteiligungAuswertung();
      result.getWahlbeteiligungAuswertungen().add(to);

      to.setBemerkung(from.getBemerkung());
      to.setStatus(from.getStatus().name());
      to.setTyp(from.getTyp().name());
      to.setWahlbeteiligungAuswertungReferenz(createWahlbeteiligungAuswertungReferenz(from));

      for (Wahlbeteiligung wahlbeteiligung : from.getWahlbeteiligungsByWahlbeteiligungAuswertung()) {
        wahlbeteiligungenImGebiet.computeIfAbsent(wahlbeteiligung.getWahldurchfuehrungsgebiet(), x -> new ArrayList<>()).add(wahlbeteiligung);
      }
    }

    for (Map.Entry<Wahldurchfuehrungsgebiet, List<Wahlbeteiligung>> entry : wahlbeteiligungenImGebiet.entrySet()) {

      Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = entry.getKey();
      List<Wahlbeteiligung> wahlbeteiligungs = entry.getValue();
      if (wahlbeteiligungs.isEmpty()) {
        continue;
      }

      ErfassteWahlbeteiligung erfassteWahlbeteiligung = new ErfassteWahlbeteiligung();
      result.getErfassteWahlbeteiligungen().add(erfassteWahlbeteiligung);
      erfassteWahlbeteiligung.setGebietReferenz(gebietMapperUtil.createGebietReferenz(wahldurchfuehrungsgebiet));
      de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung wahlbeteiligungAuswertung = wahlbeteiligungs.iterator().next()
          .getWahlbeteiligungAuswertung();

      erfassteWahlbeteiligung.setWahlart(wahlbeteiligungAuswertung.getWahl().getWahlart().getName());
      erfassteWahlbeteiligung.setWahldatum(wahlbeteiligungAuswertung.getWahl().getWahltermin().getWahldatum());
      erfassteWahlbeteiligung.setWahlterminNummer(wahlbeteiligungAuswertung.getWahl().getWahltermin().getNummer());

      for (Wahlbeteiligung wahlbeteiligung : wahlbeteiligungs) {
        erfassteWahlbeteiligung.getWahlbeteiligungen().add(mappe(wahlbeteiligung));
      }
    }

    return result;
  }

  private WahlbeteiligungAuswertungReferenz createWahlbeteiligungAuswertungReferenz(de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung from) {
    WahlbeteiligungAuswertungReferenz wahlbeteiligungAuswertungReferenz = new WahlbeteiligungAuswertungReferenz();
    wahlbeteiligungAuswertungReferenz.setDatum(from.getDatum());
    return wahlbeteiligungAuswertungReferenz;
  }

  private de.ivu.elect.interfaces.was.wahlbeteiligung.Wahlbeteiligung mappe(Wahlbeteiligung from) {
    de.ivu.elect.interfaces.was.wahlbeteiligung.Wahlbeteiligung to = new de.ivu.elect.interfaces.was.wahlbeteiligung.Wahlbeteiligung();
    to.setWahlbeteiligungAuswertungReferenz(createWahlbeteiligungAuswertungReferenz(from.getWahlbeteiligungAuswertung()));
    to.setAnzahlWaehlerGesamt(from.getAnzahlWaehlerGesamt());
    to.setAnzahlWaehlerMitWahlschein(from.getAnzahlWaehlerMitWahlschein());
    to.setErfasser(from.getErfasser());
    to.setZeitstempel(from.getZeitstempel());
    return to;
  }

  public List<de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung> mappeAuswertungen(WahlbeteiligungExchange exchange) {

    List<de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung> result = new ArrayList<>();

    Map<WahlbeteiligungAuswertungReferenz, de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung> referenzen = new HashMap<>();

    for (WahlbeteiligungAuswertung from : exchange.getWahlbeteiligungAuswertungen()) {
      de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung to = new de.ivu.elect.business.wahlbeteiligung.entity.WahlbeteiligungAuswertung();

      to.setBemerkung(from.getBemerkung());
      to.setStatus(WahlbeteiligungAuswertungStatus.valueOf(from.getStatus()));
      to.setTyp(WahlbeteiligungAuswertungTyp.valueOf(from.getTyp()));
      WahlbeteiligungAuswertungReferenz wahlbeteiligungAuswertungReferenz = from.getWahlbeteiligungAuswertungReferenz();
      to.setDatum(wahlbeteiligungAuswertungReferenz.getDatum());

      referenzen.put(wahlbeteiligungAuswertungReferenz, to);
      result.add(to);
    }

    Map<GebietReferenz, Gebiet> gebieteMap = new HashMap<>();

    Map<Gebiet, Wahldurchfuehrungsgebiet> wahldurchfuehrunsgebieteMap = new HashMap<>();
    for (ErfassteWahlbeteiligung erfassteWahlbeteiligung : exchange.getErfassteWahlbeteiligungen()) {
      Gebiet gebiet = gebietMapperUtil.createGebiet(erfassteWahlbeteiligung.getGebietReferenz(), gebieteMap);
      Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = wahldurchfuehrunsgebieteMap.computeIfAbsent(gebiet, x -> {
        Wahldurchfuehrungsgebiet wdg = wahldurchfuehrungsgebietFactory.create();
        wdg.setGebietsart(gebiet.getGebietsart());
        wdg.setNummer(gebiet.getNummer());
        return wdg;
      });
      for (de.ivu.elect.interfaces.was.wahlbeteiligung.Wahlbeteiligung from : erfassteWahlbeteiligung.getWahlbeteiligungen()) {
        Wahlbeteiligung to = new Wahlbeteiligung();
        to.setWahldurchfuehrungsgebiet(wahldurchfuehrungsgebiet);
        to.setAnzahlWaehlerGesamt(from.getAnzahlWaehlerGesamt());
        to.setAnzahlWaehlerMitWahlschein(from.getAnzahlWaehlerMitWahlschein());
        to.setWahlbeteiligungAuswertung(referenzen.get(from.getWahlbeteiligungAuswertungReferenz()));
        to.setErfasser(from.getErfasser());
        to.setZeitstempel(from.getZeitstempel());
      }

    }

    return result;

  }
}
