
package de.ivu.elect.dokumente.stimmeingabe;

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

import java.math.BigDecimal;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.annotation.Nullable;

import de.ivu.document.generator.template.BaseDocument;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;

public abstract class AbstractStimmenDocument extends BaseDocument {

  private static final long serialVersionUID = 1L;

  // Stimmzettelposition mit Lücken, z.B. "4"
  @DocumentSimpleField("Position")
  public Long position;

  @DocumentSimpleField("Position-Formatiert")
  public String positionFormatted;

  @DocumentSimpleField("Kennzahl-Formatiert")
  public String kennzahlFormatted;

  // Kennbuchstabe od. -ziffern, z.B. "D04"
  @DocumentSimpleField("Kennung")
  public String kennung;

  @DocumentSimpleField("Bezeichnung")
  public String bezeichnung;

  @DocumentSimpleField("Eingaben-Anzahlen-Stimmen-Excluded")
  public final boolean eingabenAnzahlenStimmenExcluded;

  protected AbstractStimmenDocument(boolean eingabenAnzahlenStimmenExcluded) {
    super();

    this.eingabenAnzahlenStimmenExcluded = eingabenAnzahlenStimmenExcluded;
  }

  @Nullable // Bspw. bei Lücken zwischen Listenkandidaturen der LTW...
  protected Object getTk() {
    return position;
  }

  public void addToDocumentKumuliert(StimmeingabeDocumentContext context, CoreStimmeingabeDocumentBuilder stimmeingabeDocumentBuilder, AbstractStimmenDocument stimmenDocument) {
    stimmenDocument.position = position;

    stimmenDocument.positionFormatted = positionFormatted;
    stimmenDocument.kennzahlFormatted = kennzahlFormatted;

    stimmenDocument.kennung = kennung;
    stimmenDocument.bezeichnung = bezeichnung;
  }

  protected static <T extends AbstractStimmenDocument> SortedMap<Object, T> collectStimmenDocumentToAggregatePerTk(List<T> stimmenDocuments) {
    return new TreeMap<>(stimmenDocuments.stream() //
        .filter(stimmenDocument -> (stimmenDocument.getTk() != null)) //
        .collect(toMap(T::getTk, stimmenDocument -> stimmenDocument)));
  }

  public static Long aggregate(@Nullable Long target, Long source) {
    if (target != null || source != null) {
      return fixNullToZero(target) + fixNullToZero(source);
    }

    return null;
  }

  private static Long fixNullToZero(@Nullable Long value) {
    if (value == null) {
      return 0L;
    }

    return value;
  }

  public static BigDecimal aggregate(@Nullable BigDecimal target, BigDecimal source) {
    if (target != null || source != null) {
      return fixNullToZero(target).add(fixNullToZero(source));
    }

    return null;
  }

  private static BigDecimal fixNullToZero(@Nullable BigDecimal value) {
    if (value == null) {
      return BigDecimal.ZERO;
    }

    return value;
  }
}
