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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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.gebietsbaum.control.GebietByBreadthFirstComparator;
import de.ivu.elect.business.gebietsbaum.entity.Wahldurchfuehrungsgebiet;
import de.ivu.elect.business.wahlvorschlag.entity.ReferendumOption;
import de.ivu.elect.core.exchange.stimmen.csv.AbstractStimmenCsvExportMapper;

public class ReferendumCsvErgebnisExportMapper extends AbstractStimmenCsvExportMapper<ReferendumErgebnisDTO> {

  public static final String FILE_FORMAT_NAME = "file.format.ergebnis.export.referendum";

  public ReferendumCsvErgebnisExportMapper() {
    super();
  }

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

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

    return context.getWahl().isReferendum();
  }

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

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

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

    ErgebnisDaten ergebnisDaten = exportObject.getErgebnisDaten();

    List<Wahldurchfuehrungsgebiet> wahldurchfuehrungsgebieteSortiert = new ArrayList<>(ergebnisDaten.getGebiete());
    Collections.sort(wahldurchfuehrungsgebieteSortiert, new GebietByBreadthFirstComparator());

    List<ReferendumOption> referendumOptionenSortiert = ergebnisDaten.getReferendumOptionen();
    Collections.sort(referendumOptionenSortiert, new ReferendumOptionFuerExportComparator());

    for (Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet : wahldurchfuehrungsgebieteSortiert) {
      List<ReferendumOption> referendumOptionenFuerGebiet = bestimmeReferendumOptionenFuerGebiet(wahldurchfuehrungsgebiet, referendumOptionenSortiert);

      if (!referendumOptionenFuerGebiet.isEmpty()) {
        ReferendumErgebnisDTO referendumErgebnisDTO = new ReferendumErgebnisDTO();
        mapGebietAndKopfzahlen(referendumErgebnisDTO, ergebnisDaten, wahldurchfuehrungsgebiet);

        result.add(referendumErgebnisDTO);

        ergaenzeVorlagen(referendumErgebnisDTO, wahldurchfuehrungsgebiet, ergebnisDaten, referendumOptionenSortiert);
      }
    }

    return result;
  }

  private void ergaenzeVorlagen(ReferendumErgebnisDTO referendumErgebnisDTO, Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, ErgebnisDaten ergebnisDaten,
      List<ReferendumOption> alleOptionenSortiert) {
    for (ReferendumOption referendumOption : alleOptionenSortiert) {
      ReferendumErgebnisOptionDTO option = new ReferendumErgebnisOptionDTO();

      referendumErgebnisDTO.getOptionen().add(option);

      if (referendumOption.getGebiet().equals(wahldurchfuehrungsgebiet) || wahldurchfuehrungsgebiet.isUntergebietVon(referendumOption.getGebiet())) {
        option.setVorlagenText(referendumOption.getGruppe().getName());
        option.setOption(referendumOption.getLabel());
        option.setAnzahlGueltigerStimmen(ergebnisDaten.getErgebnisDatenReferendumOptionen().getStimmenFuerReferendumOption(referendumOption, wahldurchfuehrungsgebiet));
      }
    }
  }

  private List<ReferendumOption> bestimmeReferendumOptionenFuerGebiet(Wahldurchfuehrungsgebiet wahldurchfuehrungsgebiet, List<ReferendumOption> alleOptionen) {
    List<ReferendumOption> result = new ArrayList<>();

    for (ReferendumOption referendumOption : alleOptionen) {
      if (wahldurchfuehrungsgebiet.equals(referendumOption.getGebiet()) || wahldurchfuehrungsgebiet.isUntergebietVon(referendumOption.getGebiet())) {
        result.add(referendumOption);
      }
    }

    return result;
  }
}
