
package de.ivu.elect.business.kandidatur.boundary;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;

import org.apache.deltaspike.core.api.scope.ConversationGroup;
import org.apache.deltaspike.core.api.scope.GroupedConversationScoped;

import de.ivu.elect.business.gebietsbaum.boundary.GebietSelectChangeEvent;
import de.ivu.elect.business.gebietsbaum.entity.EntityMitGebietVeraenderbar;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.control.GruppeByKurznameComparator;
import de.ivu.elect.business.gruppe.entity.EntityMitGruppe;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.kandidatur.entity.Direktkandidatur;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.business.kandidatur.entity.KandidaturProperties;
import de.ivu.elect.business.kandidatur.entity.KandidaturStatus;
import de.ivu.elect.business.person.boundary.SearchParametersMitPersonendatenNamen;
import de.ivu.elect.business.person.entity.PersonStatus;
import de.ivu.elect.business.wahlvorschlag.entity.Direktkandidat;
import de.ivu.elect.business.wahlvorschlag.entity.Wahlvorschlag;
import de.ivu.elect.jee.entity.customdata.EmptyCustomData;
import de.ivu.elect.jee.presentation.dynamicform.AbstractBooleanFilterKriteriumProperty;
import de.ivu.elect.jee.presentation.dynamicform.BooleanFilterKriterium;
import de.ivu.elect.jee.presentation.dynamicform.Property;
import de.ivu.elect.presentation.gruppe.form.GruppeSearchProperty;


import static java.util.Objects.isNull;

@GroupedConversationScoped
@ConversationGroup(AbstractKandidaturSearchParameters.class)
public class KandidaturSearchParameters extends AbstractKandidaturSearchParameters implements SearchParametersMitPersonendatenNamen, EntityMitGruppe<PolitischeGruppe>, EntityMitGebietVeraenderbar {

  private static final long serialVersionUID = 1L;

  private Gebiet gebiet;

  private PolitischeGruppe politischeGruppe;

  private Direktkandidatur kandidatur;

  private BooleanFilterKriterium freieBerufsangabe = null;

  private BooleanFilterKriterium berufsschluesselVorhanden = null;

  public KandidaturSearchParameters() {
    super();
  }

  @Override
  public Gebiet getGebiet() {
    return gebiet;
  }

  @Override
  public void setGebiet(Gebiet gebiet) {
    this.gebiet = gebiet;
  }

  @Override
  public PolitischeGruppe getGruppe() {
    return politischeGruppe;
  }

  @Override
  public void setGruppe(PolitischeGruppe politischeGruppe) {
    this.politischeGruppe = politischeGruppe;
  }

  public Property getPolitischeGruppeProperty(List<PolitischeGruppe> allePolitischenGruppen, Map<Gruppe, Set<Wahlvorschlag>> alleWahlvorschlaegeProGruppe) {
    return new GruppeSearchProperty<>(this, getPolitischeGruppenMitWahlvorschlagInGebietOderDarunter(allePolitischenGruppen, alleWahlvorschlaegeProGruppe),
        true);
  }

  protected List<PolitischeGruppe> getPolitischeGruppenMitWahlvorschlagInGebietOderDarunter(List<PolitischeGruppe> allePolitischenGruppen, Map<Gruppe, Set<Wahlvorschlag>> alleWahlvorschlaegeProGruppe) {
    return allePolitischenGruppen.stream()
        .filter(politischeGruppe -> politischeGruppe.hatWahlvorschlagInGebietOderDarunter(getGebiet(), alleWahlvorschlaegeProGruppe))
        .sorted(new GruppeByKurznameComparator<>()).collect(Collectors.toList());
  }

  private Kandidatur getKandidatur() {
    if (isNull(kandidatur)) {
      kandidatur = new Direktkandidatur(EmptyCustomData.INSTANCE);
      kandidatur.setDirektkandidat(new Direktkandidat());
      kandidatur.getDirektkandidat().setGruppeImGebiet(new GruppeImGebiet(EmptyCustomData.INSTANCE));
      kandidatur.setPersonStatus(null);
      kandidatur.setPersonenregisterAbgleichStatus(null);
      kandidatur.setKandidaturStatus(null);
    }

    return kandidatur;
  }

  private KandidaturProperties getKandidaturProperties() {
    return getKandidatur().getProperties();
  }

  public PersonStatus getPersonStatus() {
    return getKandidatur().getPersonStatus();
  }

  public Property getPersonStatusProperty() {
    return getKandidaturProperties().getPersonStatusMitLeererAuswahlProperty();
  }

  public KandidaturStatus getKandidaturStatus() {
    return getKandidatur().getKandidaturStatus();
  }

  public Property getKandidaturStatusProperty() {
    Property property = getKandidaturProperties().getKandidaturStatusMitLeererAuswahlProperty();
    property.setRequired(false);

    return property;
  }

  @Override
  @Nullable
  public String getVorname() {
    return getKandidatur().getRufname();
  }

  @Override
  public void setVorname(String vorname) {
    getKandidatur().setRufname(vorname);
  }

  @Override
  public Property getVornameProperty() {
    Property property = getKandidaturProperties().getRufnameProperty();
    property.setRequired(false);
    property.setLabel(getMessage(SearchParametersMitPersonendatenNamen.MESSAGE_KEY_VORNAME_EINZAHL));

    return property;
  }

  @Override
  @Nullable
  public String getFamilienname() {
    return getKandidatur().getFamilienname();
  }

  @Override
  public void setFamilienname(String familienname) {
    getKandidatur().setFamilienname(familienname);
  }

  @Override
  public Property getFamiliennameProperty() {
    return getKandidaturProperties().getFamiliennameProperty();
  }

  @Override
  public void onGebietSelectChangeEvent(@Observes(notifyObserver = Reception.IF_EXISTS) GebietSelectChangeEvent event) {
    super.onGebietSelectChangeEvent(event);

    setGebiet(event.getNeueEntity());
  }

  public BooleanFilterKriterium getFreieBerufsangabe() {
    return freieBerufsangabe;
  }

  public void setFreieBerufsangabe(BooleanFilterKriterium freieBerufsangabe) {
    this.freieBerufsangabe = freieBerufsangabe;
  }

  public Property getFreieBerufsangabeProperty() {
    return new FreieBerufsangabeProperty(this);
  }

  public BooleanFilterKriterium getBerufsschluesselVorhanden() {
    return berufsschluesselVorhanden;
  }

  public void setBerufsschluesselVorhanden(BooleanFilterKriterium berufsschluesselVorhanden) {
    this.berufsschluesselVorhanden = berufsschluesselVorhanden;
  }

  public Property getBerufsschluesselVorhandenProperty() {
    return new BerufsschluesselVorhandenProperty(this);
  }

  @Override
  public void reset() {
    politischeGruppe = null;
    kandidatur = null;
    freieBerufsangabe = null;

    super.reset();
  }

  public static final class FreieBerufsangabeProperty extends AbstractBooleanFilterKriteriumProperty {

    KandidaturSearchParameters searchParameters;

    public FreieBerufsangabeProperty(KandidaturSearchParameters searchParameters) {
      this.searchParameters = searchParameters;
    }

    @Override
    public BooleanFilterKriterium getValue() {
      return searchParameters.getFreieBerufsangabe();
    }

    @Override
    public void setValue(BooleanFilterKriterium booleanFilterKriterium) {
      searchParameters.setFreieBerufsangabe(booleanFilterKriterium);
    }

    @Override
    public String getDefaultLabel() {
      return getMessage("kandidatur.search.parameter.freie.berufsangabe");
    }
  }

  public static final class BerufsschluesselVorhandenProperty extends AbstractBooleanFilterKriteriumProperty {

    KandidaturSearchParameters searchParameters;

    public BerufsschluesselVorhandenProperty(KandidaturSearchParameters searchParameters) {
      this.searchParameters = searchParameters;
    }

    @Override
    public BooleanFilterKriterium getValue() {
      return searchParameters.getBerufsschluesselVorhanden();
    }

    @Override
    public void setValue(BooleanFilterKriterium booleanFilterKriterium) {
      searchParameters.setBerufsschluesselVorhanden(booleanFilterKriterium);
    }

    @Override
    public String getDefaultLabel() {
      return getMessage("kandidatur.search.parameter.berufsschluessel.vorhanden");
    }
  }
}
