
package de.ivu.elect.core.exchange.stimmen.csv;

import static de.ivu.elect.jee.entity.EntityUtil.castTo;

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

import de.ivu.elect.business.ergebnis.control.ErgebnisDaten;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportContext;
import de.ivu.elect.business.ergebnis.control.ErgebnisExportObject;
import de.ivu.elect.business.ergebnis.control.StimmenPool;
import de.ivu.elect.business.ergebnis.entity.Stimmen;
import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppe;
import de.ivu.elect.business.wahl.entity.Wahl;

public class ZweiStimmenCsvExportMapper extends AbstractStimmenCsvExportMapper<ZweiStimmenCsvDTO> {

  public static final String FILE_FORMAT_NAME = "file.format.direktstimmen.und.listenstimmen";

  public ZweiStimmenCsvExportMapper() {
    super();
  }

  @Override
  public boolean isAcceptContext(ErgebnisExportContext context) {
    if (!super.isAcceptContext(context)) {
      return false;
    }

    if (context == null || !context.hasWahl()) {
      return false;
    }

    Wahl wahl = context.getWahl();

    return wahl.isWahlMitDirektkandidatengebieten() && wahl.isWahlMitListengebieten();
  }

  @Override
  protected String getFileFormatName() {
    return FILE_FORMAT_NAME;
  }

  @Override
  protected Class<ZweiStimmenCsvDTO> getStimmenCsvDTOClass() {
    return ZweiStimmenCsvDTO.class;
  }

  @Override
  protected List<ZweiStimmenCsvDTO> mappeEntityInternToExtern(ErgebnisExportObject exportObject, ErgebnisExportContext context) {
    List<ZweiStimmenCsvDTO> result = new ArrayList<>();

    ErgebnisDaten ergebnisDaten = exportObject.getErgebnisDaten();

    StimmenPool stimmenPool = ergebnisDaten.getStimmen();
    List<Stimmen> stimmen = stimmenPool.getSystemgruppenStimmen();

    for (Gruppe gruppe : ergebnisDaten.getGruppen()) {
      // ELECTMUC-752
      //
      // Gültige und ungültige Stimmen wurden doppelt gezählt da daten.getGruppen()
      // nicht nur politische Gruppen zurückgibt.
      //

      if (gruppe.isPolitischeGruppe()) {
        stimmen.addAll(stimmenPool.getDirektstimmen(gruppe));
        stimmen.addAll(stimmenPool.getListenstimmenDerGruppe(gruppe));
      }
    }

    Map<Gebiet, Map<Gruppe, List<Stimmen>>> stimmenByGebietUndGruppe = aggregateStimmenByGebietUndGruppe(stimmen);

    for (Gebiet gebiet : getSortedGebiete(stimmenByGebietUndGruppe)) {
      Map<Gruppe, List<Stimmen>> entry = stimmenByGebietUndGruppe.get(gebiet);

      Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet = castTo(gebiet, Wahldurchfuehrungsgebiet.class);

      ZweiStimmenCsvDTO dto = new ZweiStimmenCsvDTO();
      mapGebietAndKopfzahlen(dto, ergebnisDaten, wahldurchfuehrungsgebiet);

      dto.setPolitischeGruppenStimmen(new ArrayList<ZweiGruppeStimmenDTO>());

      for (Entry<Gruppe, List<Stimmen>> entryPerGruppe : entry.entrySet()) {
        Gruppe gruppe = entryPerGruppe.getKey();
        List<Stimmen> stimmenDerGruppeAufDemGebiet = entryPerGruppe.getValue();

        if (systemGruppeEigenschaften.isGruppeEqualsSystemGruppe(gruppe, SystemGruppe.GUELTIGE)) {
          addGueltigeStimmenToCsvDTO(dto, stimmenDerGruppeAufDemGebiet);
        } else if (systemGruppeEigenschaften.isGruppeEqualsSystemGruppe(gruppe, SystemGruppe.UNGUELTIGE)) {
          addUngueltigeStimmenToCsvDTO(dto, stimmenDerGruppeAufDemGebiet);
        } else if (gruppe.isPolitischeGruppe()) {
          addPolitischeGruppeStimmenToCsvDTO(dto, gruppe, stimmenDerGruppeAufDemGebiet);
        }
      }

      result.add(dto);
    }

    return result;
  }

  private void addGueltigeStimmenToCsvDTO(ZweiStimmenCsvDTO dto, List<Stimmen> stimmenDerGruppeAufDemGebiet) {
    dto.setAnzahlDirektstimmenGueltig(summiereAnzahlFuerStimmart(stimmenDerGruppeAufDemGebiet, Stimmenart.DIREKTSTIMME));
    dto.setAnzahlListenstimmenGueltig(summiereAnzahlFuerStimmart(stimmenDerGruppeAufDemGebiet, Stimmenart.LISTENSTIMME));
  }

  private void addUngueltigeStimmenToCsvDTO(ZweiStimmenCsvDTO dto, List<Stimmen> stimmenDerGruppeAufDemGebiet) {
    dto.setAnzahlDirektstimmenUngueltig(summiereAnzahlFuerStimmart(stimmenDerGruppeAufDemGebiet, Stimmenart.DIREKTSTIMME));
    dto.setAnzahlListenstimmenUngueltig(summiereAnzahlFuerStimmart(stimmenDerGruppeAufDemGebiet, Stimmenart.LISTENSTIMME));
  }

  private void addPolitischeGruppeStimmenToCsvDTO(ZweiStimmenCsvDTO dto, Gruppe gruppe, List<Stimmen> stimmenDerGruppeAufDemGebiet) {
    ZweiGruppeStimmenDTO politischeGruppeStimmen = new ZweiGruppeStimmenDTO();

    politischeGruppeStimmen.setGruppeSchluessel(gruppe.getSchluessel());
    politischeGruppeStimmen.setAnzahlDirektstimmen(summiereAnzahlFuerStimmart(stimmenDerGruppeAufDemGebiet, Stimmenart.DIREKTSTIMME));
    politischeGruppeStimmen.setAnzahlListenstimmen(summiereAnzahlFuerStimmart(stimmenDerGruppeAufDemGebiet, Stimmenart.LISTENSTIMME));
    dto.getPolitischeGruppenStimmen().add(politischeGruppeStimmen);
  }
}
