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

import static java.util.stream.Collectors.joining;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.GruppeTK;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.jee.entity.Entity;
import de.ivu.elect.jee.entity.EntityContainer;
import de.ivu.elect.jee.entity.EntityFachlichAbhaengigNode;
import de.ivu.elect.jee.entity.EntityLongPK;
import de.ivu.elect.jee.entity.tk.EntityTK;
import de.ivu.elect.jee.entity.tk.EntityUK;
import de.ivu.elect.jee.protokollierung.VorherNachherWert;

public abstract class AbstractStimmeingabeStimmen implements StimmeingabeStimmen {

  private static final long serialVersionUID = 1L;

  private final Set<String> rowStyleClasses;

  private EntityLongPK pk;

  protected AbstractStimmeingabeStimmen() {
    super();

    this.rowStyleClasses = new HashSet<>();

    this.pk = null;
  }

  @Override
  public Long getId() {
    return getPk().getId();
  }

  @Override
  public EntityLongPK getPk() {
    if (pk == null) {
      pk = createPk();
    }

    return pk;
  }

  private EntityLongPK createPk() {
    long id = hashCode();

    GruppeImGebiet gruppeImGebiet = getGruppeImGebiet();

    if (gruppeImGebiet != null) {
      id = gruppeImGebiet.getId(); // ELECT-14002
    }

    EntityLongPK entityLongPk = new EntityLongPK();
    entityLongPk.setId(id);

    return entityLongPk;
  }

  public boolean hasStimmeingaben() {
    return !getStimmeingaben().isEmpty();
  }

  public boolean hasSystemGruppenStimmeingabe() {
    for (Stimmeingabe stimmeingabe : getStimmeingaben()) {
      if (stimmeingabe.isSystemGruppenStimmeingabe()) {
        return true;
      }
    }

    return false;
  }

  public boolean hasZwischensummenStimmeingabe() {
    for (Stimmeingabe stimmeingabe : getStimmeingaben()) {
      if (stimmeingabe.isZwischensummeEingabe()) {
        return true;
      }
    }

    return false;
  }

  public boolean hasStimmeingabeDieKeineZwischensummeIst() {
    for (Stimmeingabe stimmeingabe : getStimmeingaben()) {
      if (!stimmeingabe.isZwischensummeEingabe()) {
        return true;
      }
    }

    return false;
  }

  @Override
  public boolean isPolitischeGruppe() {
    Gruppe gruppe = getGruppe();

    if (gruppe != null) {
      return gruppe.isPolitischeGruppe();
    }

    return false;
  }

  public boolean isEinzelbewerber() {
    Gruppe gruppe = getGruppe();

    if (gruppe != null) {
      return gruppe.isEinzelbewerber();
    }

    return false;
  }

  @Nullable
  public Gruppe getGruppe() {
    GruppeImGebiet gruppeImGebiet = getGruppeImGebiet();

    if (gruppeImGebiet != null) {
      return gruppeImGebiet.getGruppe();
    }

    return null;
  }

  public GruppeTK getGruppeTK() {
    Gruppe gruppe = getGruppe();

    if (gruppe != null) {
      return gruppe.getGruppeTK();
    }

    return null;
  }

  public String getGruppeSchluessel() {
    Gruppe gruppe = getGruppe();

    if (gruppe != null) {
      return gruppe.getSchluessel();
    }

    return null;
  }

  public boolean hasGruppeImGebiet() {
    return getGruppeImGebiet() != null;
  }

  @Nullable
  public GruppeImGebiet getGruppeImGebiet() {
    for (Stimmeingabe stimmeingabe : getStimmeingaben()) {
      if (stimmeingabe.hasGruppeImGebiet()) {
        return stimmeingabe.getGruppeImGebiet();
      }
    }

    return null;
  }

  protected boolean hasStimmeingabeAlphanumerisch() {
    return false;
  }

  public boolean hasVorlaeufigeStimmeingabe() {
    for (Stimmeingabe stimmeingabe : getStimmeingaben()) {
      if (stimmeingabe.isErgebniseingangVorlaeufig()) {
        return true;
      }
    }

    return false;
  }

  public boolean hasEndgueltigeStimmeingabe() {
    for (Stimmeingabe stimmeingabe : getStimmeingaben()) {
      if (stimmeingabe.isErgebniseingangEndgueltig()) {
        return true;
      }
    }

    return false;
  }

  public void setVisible(boolean visible) {
    if (visible) {
      rowStyleClasses.remove(STYLE_CLASS_HIDDEN);
    } else {
      rowStyleClasses.add(STYLE_CLASS_HIDDEN);
    }
  }

  @Override
  public String getRowStyleClass() {
    return " " + getGruppeSchluessel() + " " + getStimmeingabefehlerStyleClass(getStimmeingabefehlerLetzterErgebniseingang()) + " "
        + rowStyleClasses.stream().filter(StringUtils::isNotBlank).collect(joining(" ")) + " ";
  }

  public void addRowStyleClass(String styleClass) {
    rowStyleClasses.add(styleClass);
  }

  protected String getStimmeingabeStyleClass(Collection<Stimmeingabefehler> stimmeingabefehler) {
    String result = " ";

    if (hasStimmeingabeAlphanumerisch()) {
      result += StimmeingabeStimmen.STYLE_CLASS_NUMBER_LETTER;
    } else {
      result += StimmeingabeStimmen.STYLE_CLASS_NUMBER;
    }

    return result + " " + getStimmeingabefehlerStyleClass(stimmeingabefehler) + " ";
  }

  private String getStimmeingabefehlerStyleClass(Collection<Stimmeingabefehler> stimmeingabefehler) {
    String result = "";

    if (containsMussStimmeingabefehler(stimmeingabefehler)) {
      result += " " + StimmeingabeStimmen.STYLE_CLASS_ERROR + " ";
    } else if (containsKannStimmeingabefehler(stimmeingabefehler)) {
      result += " " + StimmeingabeStimmen.STYLE_CLASS_WARNING + " ";
    }

    return result;
  }

  public boolean hasStimmeingabefehler() {
    return !getStimmeingabefehlerLetzterErgebniseingang().isEmpty();
  }

  protected boolean containsKannStimmeingabefehler(Collection<Stimmeingabefehler> stimmeingabefehler) {
    return stimmeingabefehler.stream().anyMatch(AbstractStimmeingabefehler::isKannFehler);
  }

  protected boolean containsMussStimmeingabefehler(Collection<Stimmeingabefehler> stimmeingabefehler) {
    return stimmeingabefehler.stream().anyMatch(AbstractStimmeingabefehler::isMussFehler);
  }

  @Override
  public boolean isAenderungenProtokollieren() {
    return false;
  }

  @Override
  public Map<String, VorherNachherWert> getProtokollierteAttributeMitWerten() {
    throw new UnsupportedOperationException();
  }

  @Override
  public void resetProtokollierteAttribute() {
  }

  @Override
  public List<EntityFachlichAbhaengigNode> getFachlichAbhaengigeEntitaeten() {
    throw new UnsupportedOperationException();
  }

  @Override
  public EntityTK getTk() {
    throw new UnsupportedOperationException();
  }

  @Override
  public EntityUK getUk() {
    throw new UnsupportedOperationException();
  }

  @Override
  public Class< ? > getEntityClass() {
    return getClass();
  }

  @Override
  public String getEntityTechnicalName() {
    throw new UnsupportedOperationException();
  }

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

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

  public static List<Stimmeingabe> extractStimmeingaben(Collection< ? extends StimmeingabeStimmen> stimmeingabeValues) {
    List<Stimmeingabe> result = new ArrayList<>();

    for (StimmeingabeStimmen stimmeingabeValue : stimmeingabeValues) {
      result.addAll(stimmeingabeValue.getStimmeingaben());
    }

    return result;
  }

  @Override
  public void copyEntityAttributesToOtherEntity(Entity entity) {
    throw new UnsupportedOperationException();
  }

  @Override
  public void setProtokollierteAttributeMitWerten(Map map) {
    throw new UnsupportedOperationException();
  }
}
