
package de.ivu.elect.wus.exchange.wahlvorschlag.csv;

import static org.apache.commons.lang3.StringUtils.isBlank;

import javax.annotation.Nullable;
import javax.inject.Inject;

import de.ivu.elect.business.gebietsbaum.boundary.GebietDAO;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsgruppierungDAO;
import de.ivu.elect.business.gebietsbaum.boundary.WahlverwaltungGebietDescriptor;
import de.ivu.elect.business.gebietsbaum.boundary.WahlverwaltungGebietInformationResolver;
import de.ivu.elect.business.gebietsbaum.boundary.WahlverwaltungGebietInformationResolverContext;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.kandidatur.control.WahlvorschlagExportContext;
import de.ivu.elect.business.kandidatur.entity.Direktkandidatur;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.kandidatur.entity.ListenkandidaturStimmzettelPosition;
import de.ivu.elect.business.stimmzettel.entity.EntityAufStimmzettelDaten;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagStimmzettelPosition;

public abstract class AbstractWahlvorschlagCsvInternExternMapper<T extends WahlvorschlagCsvDTO> {

  @Inject
  protected transient WahlverwaltungGebietInformationResolver wahlverwaltungGebietInformationResolver;

  @Inject
  protected transient GebietDAO gebietDAO;

  @Inject
  protected transient GebietsgruppierungDAO gebietsgruppierungDAO;

  protected AbstractWahlvorschlagCsvInternExternMapper() {
    super();
  }

  protected abstract T createEntityDTO();

  public T mapFromWahlvorschlag(Wahlvorschlag wahlvorschlag, EntityAufStimmzettelDaten entityAufStimmzettelDaten, WahlvorschlagExportContext context) {
    T result = createEntityDTO();

    Wahl wahl = wahlvorschlag.getWahl();

    WahlverwaltungGebietDescriptor gebietDescriptor = createGebietDescriptor(entityAufStimmzettelDaten, wahl, wahlvorschlag.getGebiet());

    fillWahl(result, wahl, context);
    fillGebiet(result, gebietDescriptor, context);
    fillGruppe(result, wahlvorschlag.getGruppe(), context);
    fillWahlvorschlag(result, wahlvorschlag, entityAufStimmzettelDaten, context);

    return result;
  }

  protected WahlverwaltungGebietDescriptor createGebietDescriptor(EntityAufStimmzettelDaten entityAufStimmzettelDaten, Wahl wahl, Gebiet gebiet) {
    return wahlverwaltungGebietInformationResolver
        .createDescriptor(new WahlverwaltungGebietInformationResolverContext(wahl, entityAufStimmzettelDaten.getWahlParameterLoader(), gebietDAO, gebietsgruppierungDAO), gebiet);
  }

  protected void fillWahl(T dto, Wahl wahl, WahlvorschlagExportContext context) {
    // wird überschrieben
  }

  protected void fillGruppe(T dto, PolitischeGruppe gruppe, WahlvorschlagExportContext context) {
    // wird überschrieben
  }

  protected void fillGebiet(T dto, WahlverwaltungGebietDescriptor gebietDescriptor, WahlvorschlagExportContext context) {
    dto.setGebietsnummer(gebietDescriptor.getGebiet().getNummer());
  }

  protected void fillWahlvorschlag(T dto, Wahlvorschlag wahlvorschlag, EntityAufStimmzettelDaten entityAufStimmzettelDaten, WahlvorschlagExportContext context) {
    // ELECT-6957 bisheriges Verhalten
    dto.setWahlvorschlagPosition(bestimmeWahlvorschlagStimmzettelPosition(wahlvorschlag, entityAufStimmzettelDaten, context));

    GruppeImGebiet gruppeImGebiet = wahlvorschlag.getGruppeImGebiet();

    // ELECT-3864
    if (isBlank(wahlvorschlag.getKennwort())) {
      if (isBlank(gruppeImGebiet.getName())) {
        dto.setWahlvorschlagKennwort(gruppeImGebiet.getGruppe().getName());
      } else {
        dto.setWahlvorschlagKennwort(gruppeImGebiet.getName());
      }
    } else {
      dto.setWahlvorschlagKennwort(wahlvorschlag.getKennwort());
    }

    dto.setWahlvorschlagKurzname(wahlvorschlag.getKurzname());
    dto.setWahlvorschlagZusatzbezeichnung(wahlvorschlag.getZusatzbezeichnung());
  }

  public void fillListenkandidatur(T dto, Listenkandidatur listenkandidatur, EntityAufStimmzettelDaten entityAufStimmzettelDaten, WahlvorschlagExportContext context) {
    dto.setKandidaturListenposition(bestimmeListenkandidaturPosition(listenkandidatur, entityAufStimmzettelDaten, context));
    dto.setKandidaturAnzahlNennungen(listenkandidatur.getListenkandidaturArt().isErsatzkandidatur() ? 0 : listenkandidatur.getAnzahlNennungen());

    fillKandidatur(dto, listenkandidatur, entityAufStimmzettelDaten, context);
  }

  public void fillDirektkandidatur(T dto, Direktkandidatur direktkandidatur, EntityAufStimmzettelDaten entityAufStimmzettelDaten, WahlvorschlagExportContext context) {
    fillKandidatur(dto, direktkandidatur, entityAufStimmzettelDaten, context);
  }

  protected void fillKandidatur(T dto, Kandidatur kandidatur, EntityAufStimmzettelDaten entityAufStimmzettelDaten, WahlvorschlagExportContext context) {
    dto.setKandidaturTitel(kandidatur.getTitel());
    dto.setKandidaturNamensbestandteile(kandidatur.getFamiliennameBestandteil());

    dto.setKandidaturFamilienname(kandidatur.getFamilienname());
    dto.setKandidaturVorname(kandidatur.getRufname());

    dto.setKandidaturBeruf(kandidatur.getBerufUnformatiert());

    fillGeburtsdaten(dto, kandidatur, context);
  }

  protected void fillGeburtsdaten(T dto, Kandidatur kandidatur, WahlvorschlagExportContext context) {
    dto.setKandidaturGeburtsdatum(kandidatur.getGeburtsdatum(), context.getLocale());
  }

  /**
   * NOTE, dass die Stimmzettelposition nur verwendet werden kann, wenn nur Zugelassene Wahlvorschläge exportiert werden! Sonst muss auf die relative Position rückgegriffen werden.
   */
  @Nullable
  protected Long bestimmeWahlvorschlagStimmzettelPosition(Wahlvorschlag wahlvorschlag, EntityAufStimmzettelDaten entityAufStimmzettelDaten, WahlvorschlagExportContext context) {
    WahlvorschlagStimmzettelPosition stimmzettelPosition = wahlvorschlag.getStimmzettelPosition(entityAufStimmzettelDaten);

    if (stimmzettelPosition.hasPosition()) {
      return stimmzettelPosition.getPosition();
    }

    if (context.isNichtZugelasseneExportieren() || context.isUngepruefteExportieren()) {
      return wahlvorschlag.getGruppeImGebiet().getRelativePosition();
    }

    return stimmzettelPosition.getPosition();
  }

  /**
   * NOTE, dass die Stimmzettelposition nur verwendet werden kann, wenn nur zugelassene Kandidaturen exportiert werden! Sonst muss auf die relative Position rückgegriffen werden.
   */
  @Nullable
  protected Long bestimmeListenkandidaturPosition(Listenkandidatur listenkandidatur, EntityAufStimmzettelDaten entityAufStimmzettelDaten, WahlvorschlagExportContext context) {
    ListenkandidaturStimmzettelPosition stimmzettelPosition = listenkandidatur.getStimmzettelPosition(entityAufStimmzettelDaten);

    if (stimmzettelPosition.hasPosition()) {
      return stimmzettelPosition.getPosition();
    }

    if (context.isNichtZugelasseneExportieren() || context.isUngepruefteExportieren()) {
      return listenkandidatur.getRelativePosition();
    }

    return stimmzettelPosition.getPosition();
  }
}
