
package de.ivu.elect.was.exchange.stimmeingabe;

import java.io.Serializable;

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

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.gebietsbaum.boundary.WahldurchfuehrungsgebietFactory;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.boundary.GruppeFactory;
import de.ivu.elect.business.gruppe.boundary.PolitischeGruppeFactory;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppeEigenschaften;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietFactory;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.kandidatur.boundary.ListenkandidaturFactory;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.stimmeingabe.control.StimmeingabeImportContext;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingang;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;
import de.ivu.elect.business.wahl.boundary.WahldurchfuehrungDAO;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;
import de.ivu.elect.business.wahlvorschlag.entity.Liste;
import de.ivu.elect.jee.faces.Messages;

public abstract class AbstractStimmeingabeImportMapper implements StimmeingabeImportMapper, Serializable {

  private static final Long OHNE_POSITION = null;

  private static final long serialVersionUID = 1L;

  @Inject
  protected transient Messages messages;

  @Inject
  protected transient WahldurchfuehrungDAO wahldurchfuehrungDAO;

  @Inject
  protected transient SystemGruppeEigenschaften systemGruppeEigenschaften;

  @Inject
  protected transient WahldurchfuehrungsgebietFactory wahldurchfuehrungsgebietFactory;

  @Inject
  protected transient GruppeFactory gruppeFactory;

  @Inject
  protected transient PolitischeGruppeFactory politischeGruppeFactory;

  @Inject
  protected transient GruppeImGebietFactory gruppeImGebietFactory;

  @Inject
  protected transient ListenkandidaturFactory listenkandidaturFactory;

  private final Logger log;

  public AbstractStimmeingabeImportMapper() {
    super();

    this.log = LoggerFactory.getLogger(getClass());
  }

  @Override
  public boolean isAcceptContext(StimmeingabeImportContext context) {
    Wahldurchfuehrung wahldurchfuehrung = findWahl(context);

    return wahldurchfuehrung != null && isAcceptWahl(wahldurchfuehrung);
  }

  protected abstract boolean isAcceptWahl(@Nonnull Wahldurchfuehrung wahldurchfuehrung);

  protected Gruppe createWahlberechtigte() {
    return createGruppe(SystemGruppe.WAHLBERECHTIGTE);
  }

  protected Gruppe createWaehler() {
    return createGruppe(SystemGruppe.WAEHLER);
  }

  protected Gruppe createGueltige() {
    return createGruppe(SystemGruppe.GUELTIGE);
  }

  protected Gruppe createUngueltige() {
    return createGruppe(SystemGruppe.UNGUELTIGE);
  }

  @Nonnull
  protected Gruppe createGruppe(SystemGruppe systemGruppe) {
    Gruppe gruppe = createGruppe();
    gruppe.setSchluessel(systemGruppeEigenschaften.getSchluessel(systemGruppe));

    return gruppe;
  }

  protected Gruppe createGruppe() {
    return gruppeFactory.create();
  }

  protected PolitischeGruppe createPolitischeGruppe(String schluessel) {
    PolitischeGruppe politischeGruppe = politischeGruppeFactory.create();
    politischeGruppe.setSchluessel(schluessel);

    return politischeGruppe;
  }

  protected Stimmeingabe addStimmeingabeOhnePosition(Ergebniseingang result, Stimmenart stimmenart, Gruppe gruppe, String wert) {
    return addStimmeingabe(result, stimmenart, gruppe, OHNE_POSITION, wert);
  }

  protected Stimmeingabe addStimmeingabe(Ergebniseingang result, Stimmenart stimmenart, Gruppe gruppe, Long position, String wert) {
    GruppeImGebiet gruppeImGebiet = createGruppeImGebiet(gruppe, result.getGebiet(), position);

    Stimmeingabe stimmeingabe = new Stimmeingabe();
    stimmeingabe.setAnzahlEingabe(filterNull(wert));
    stimmeingabe.setStimmenart(stimmenart);
    stimmeingabe.setGruppeImGebiet(gruppeImGebiet);

    result.addStimmeingabe(stimmeingabe);

    return stimmeingabe;
  }

  protected Stimmeingabe addListenStimmeingabe(Ergebniseingang result, GruppeImGebiet gruppeImGebiet, Liste liste, Long listenkandidaturPosition, String wert) {
    Stimmeingabe stimmeingabe = new Stimmeingabe();
    stimmeingabe.setAnzahlEingabe(filterNull(wert));
    stimmeingabe.setStimmenart(Stimmenart.LISTENSTIMME);
    stimmeingabe.setGruppeImGebiet(gruppeImGebiet);

    Listenkandidatur listenkandidatur = listenkandidaturFactory.create();
    listenkandidatur.setListe(liste);
    listenkandidatur.setRelativePosition(listenkandidaturPosition);
    listenkandidatur.setVorgegebenePosition(listenkandidaturPosition);
    stimmeingabe.setListenkandidatur(listenkandidatur);

    result.addStimmeingabe(stimmeingabe);

    return stimmeingabe;
  }

  private GruppeImGebiet createGruppeImGebiet(Gruppe gruppe, Gebiet gebiet, Long position) {
    GruppeImGebiet gruppeImGebiet = gruppeImGebietFactory.create();
    gruppeImGebiet.setGebiet(gebiet);
    gruppeImGebiet.setGruppe(gruppe);
    gruppeImGebiet.setRelativePosition(position);
    gruppeImGebiet.setVorgegebenePosition(position);

    return gruppeImGebiet;
  }

  @Nullable
  protected String filterNull(String wert) {
    if (wert == null || StringUtils.isBlank(wert)) {
      return null;
    }

    return wert;
  }

  protected Wahldurchfuehrung findWahl(StimmeingabeImportContext context) {
    return wahldurchfuehrungDAO.attach(context.getWahldurchfuehrung()); // ELECT-10878
  }

  protected String getMessage(String msgKey, Object... params) {
    return getMessages().getMessageForMessageKey(msgKey, params);
  }

  protected String getMessage(Enum< ? > enumValue) {
    return getMessages().lokalisiere(enumValue);
  }

  protected Messages getMessages() {
    return messages;
  }

  protected void debug(String format, Object... params) {
    getLog().debug(format, params);
  }

  protected void info(String format, Object... params) {
    getLog().info(format, params);
  }

  protected void warn(String format, Object... params) {
    getLog().warn(format, params);
  }

  protected void error(String format, Throwable cause) {
    getLog().error(format, cause);
  }

  private Logger getLog() {
    return log;
  }
}
