
package de.ivu.elect.business.stimmeingabe.entity;

import static java.util.stream.Collectors.joining;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.ergebnis.entity.Stimmenart;
import de.ivu.elect.business.stimmeingabe.control.plausi.StimmeingabePlausi;
import de.ivu.elect.jee.entity.EntityContainer;
import de.ivu.elect.jee.entity.tk.EntityTK;
import de.ivu.elect.jee.presentation.dynamicform.AbstractStringProperty;

/**
 * Eine Zeile in der GUI zur Eingabe einer Kopfzahl.
 */
public class StimmeingabeKopfzahl extends AbstractStimmeingabeStimmen {

  private static final long serialVersionUID = 1L;

  private final String kennung;

  private final String bezeichnung;

  private boolean readonly;

  private final Stimmeingabe stimmeingabe;

  private final String stimmeingabeKennung;

  private final String stimmeingabeBezeichnung;

  private final String anzahlEingabeExpected;

  private final Long anzahlExpected;

  private final List<Stimmeingabefehler> stimmeingabefehlerLetzterErgebniseingang;

  private final Stimmeingabe stimmeingabeVergleich;

  private final Set<String> stimmeingabeStyleClasses;

  public StimmeingabeKopfzahl(String kennung, String bezeichnung, Stimmeingabe stimmeingabe, String stimmeingabeKennung, String stimmeingabeBezeichnung, @Nullable String anzahlEingabeExpected,
      @Nullable Long anzahlExpected, List<Stimmeingabefehler> stimmeingabefehlerLetzterErgebniseingang, @Nullable Stimmeingabe stimmeingabeVergleich) {
    super();

    this.kennung = kennung;
    this.bezeichnung = bezeichnung;
    this.readonly = false;

    this.stimmeingabe = stimmeingabe;
    this.stimmeingabeKennung = stimmeingabeKennung;
    this.stimmeingabeBezeichnung = stimmeingabeBezeichnung;

    this.anzahlEingabeExpected = anzahlEingabeExpected;
    this.anzahlExpected = anzahlExpected;

    this.stimmeingabefehlerLetzterErgebniseingang = stimmeingabefehlerLetzterErgebniseingang;

    this.stimmeingabeVergleich = stimmeingabeVergleich;

    this.stimmeingabeStyleClasses = new HashSet<>();
  }

  @Override
  public String getKennung() {
    return kennung;
  }

  @Override
  public String getBezeichnung() {
    return bezeichnung;
  }

  public boolean isReadonly() {
    return readonly;
  }

  public void setReadonly(boolean readonly) {
    this.readonly = readonly;
  }

  public boolean isAnzahlExpectedChecked() {
    return hasAnzahlEingabeExpected() || hasAnzahlExpected();
  }

  public boolean hasAnzahlEingabeExpected() {
    return isNotBlank(getAnzahlEingabeExpected());
  }

  @Nullable
  public String getAnzahlEingabeExpected() {
    return anzahlEingabeExpected;
  }

  public boolean hasAnzahlExpected() {
    return getAnzahlExpected() != null;
  }

  @Nullable
  public Long getAnzahlExpected() {
    return anzahlExpected;
  }

  public boolean hasAnzahl() {
    return hasStimmeingabe() && getStimmeingabe().hasAnzahlGroesserGleichNull();
  }

  public Long getAnzahl() {
    return getStimmeingabe().getAnzahl();
  }

  public boolean isAnzahlEingabeRendered() {
    return hasStimmeingabe();
  }

  public boolean hasAnzahlEingabe() {
    return isNotBlank(getAnzahlEingabe());
  }

  public String getAnzahlEingabeOrDefault(String defaultValue) {
    if (hasStimmeingabeAlphanumerisch()) {
      return trimToEmpty(getAnzahlEingabe()); // ELECT-11813
    }

    return defaultIfBlank(getAnzahlEingabe(), trimToEmpty(defaultValue));
  }

  public String getAnzahlEingabe() {
    return getStimmeingabeAnzahlEingabeProperty().getValue();
  }

  public void setAnzahlEingabe(String value) {
    getStimmeingabeAnzahlEingabeProperty().setValue(value);
  }

  private AbstractStringProperty getStimmeingabeAnzahlEingabeProperty() {
    return getStimmeingabe().getProperties().getAnzahlEingabeProperty();
  }

  @Override
  protected boolean hasStimmeingabeAlphanumerisch() {
    return super.hasStimmeingabeAlphanumerisch() || hasStimmeingabe() && getStimmeingabe().isPruefkennzeichenEingabe();
  }

  private boolean hasStimmeingabe() {
    return getStimmeingabe() != null;
  }

  public Stimmeingabe getStimmeingabe() {
    return stimmeingabe;
  }

  @Override
  public Collection<Stimmeingabe> getStimmeingaben() {
    if (hasStimmeingabe()) {
      return Collections.singleton(getStimmeingabe());
    }

    return Collections.emptyList();
  }

  public String getStimmeingabeKennung() {
    return stimmeingabeKennung;
  }

  public String getStimmeingabeBezeichnung() {
    return stimmeingabeBezeichnung;
  }

  public String getStimmeingabeStyleClass() {
    return getStimmeingabeStyleClass(getStimmeingabefehlerLetzterErgebniseingang()) + " " + stimmeingabeStyleClasses.stream().filter(StringUtils::isNotBlank).collect(joining(" ")) + " ";
  }

  public void addStimmeingabeStyleClass(String styleClass) {
    stimmeingabeStyleClasses.add(styleClass);
  }

  @Override
  public String getRowStyleClass() {
    String result = super.getRowStyleClass();

    Stimmenart stimmenart = getStimmenart();

    if (stimmenart != null) {
      result += " " + stimmenart.name() + " ";
    }

    return result;
  }

  @Nullable
  public Stimmenart getStimmenart() {
    if (hasStimmeingabe()) {
      return getStimmeingabe().getStimmenart();
    }

    return null;
  }

  @Override
  public List<Stimmeingabefehler> getStimmeingabefehlerLetzterErgebniseingang() {
    return stimmeingabefehlerLetzterErgebniseingang;
  }

  public void addPlausi(StimmeingabePlausi stimmeingabePlausi) {
    getStimmeingabe().addStimmeingabePlausi(stimmeingabePlausi);
  }

  public boolean hasAnzahlEingabeVergleich() {
    return hasStimmeingabeVergleich() && getStimmeingabeVergleich().hasAnzahlEingabe();
  }

  public String getAnzahlEingabeVergleichOrDefault(String defaultValue) {
    if (hasStimmeingabeVergleichAlphanumerisch()) {
      return trimToEmpty(getAnzahlEingabeVergleich()); // ELECT-11813
    }

    if (hasStimmeingabeVergleich()) {
      return defaultIfBlank(getAnzahlEingabeVergleich(), trimToEmpty(defaultValue));
    }

    return "";
  }

  public String getAnzahlEingabeVergleich() {
    return getStimmeingabeVergleich().getAnzahlEingabe();
  }

  public boolean hasAnzahlVergleich() {
    return hasStimmeingabeVergleich() && getStimmeingabeVergleich().hasAnzahlGroesserGleichNull();
  }

  public Long getAnzahlVergleich() {
    return getStimmeingabeVergleich().getAnzahl();
  }

  protected boolean hasStimmeingabeVergleichAlphanumerisch() {
    return hasStimmeingabeVergleich() && getStimmeingabeVergleich().isPruefkennzeichenEingabe();
  }

  public boolean hasStimmeingabeVergleich() {
    return getStimmeingabeVergleich() != null;
  }

  public Stimmeingabe getStimmeingabeVergleich() {
    return stimmeingabeVergleich;
  }

  @Override
  public boolean hasTk(EntityTK tk) {
    return hasStimmeingabe() && getStimmeingabe().getTk().equals(tk);
  }

  @Override
  public boolean isInstanceOf(Class< ? > clazz) {
    return false;
  }

  @Override
  public <E> EntityContainer<E> castTo(Class<E> clazz) {
    throw new UnsupportedOperationException();
  }

  @Override
  public String getBaseClassName() {
    return getClass().getName();
  }
}
