
package de.ivu.elect.presentation.ergebnis.dokumente.gesamtergebnis;

import static de.ivu.elect.was.exchange.ergebnis.dokumente.util.WahlbuchNumberUtil.subtractLongNull;

import java.math.BigDecimal;

import javax.annotation.Nullable;

import de.ivu.document.generator.template.BaseDocument;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.elect.dokumente.DokumentFormatter;
import de.ivu.elect.presentation.system.PercentUtil;

/**
 * Paar von zwei Angaben zu einem Stimmergebnis o.ä.. Erstens die Anzahl der Stimmen, zweitens der prozentuale Anteil
 * bezogen auf einen gegebenen Gesamtwert / Bezugsgröße.
 */
public class AnzahlMitProzent extends BaseDocument {

  @DocumentSimpleField("Anzahl")
  public final Long anzahl;

  @DocumentSimpleField("Prozent")
  public final BigDecimal prozent;

  @DocumentSimpleField("AnzahlFormatiert")
  public final String anzahlFormatiert;

  @DocumentSimpleField("ProzentFormatiert")
  public final String prozentFormatiert;

  /**
   * Dieser Konstruktor sollte BEVORZUGT verwendet werden.
   */
  public AnzahlMitProzent(@Nullable Long anzahl, @Nullable Long bezugsgroesse, DokumentFormatter formatter) {
    this(anzahl, createProzent(anzahl, bezugsgroesse), formatter);
  }

  public AnzahlMitProzent(@Nullable Long anzahl, @Nullable Long bezugsgroesse, DokumentFormatter formatter,
      boolean isDifferenz) {
    this(anzahl, createProzent(anzahl, bezugsgroesse), formatter, isDifferenz);
  }

  public AnzahlMitProzent(@Nullable Long anzahl, @Nullable BigDecimal prozent, DokumentFormatter formatter) {
    this(anzahl, prozent, formatter, false);
  }

  protected AnzahlMitProzent(@Nullable Long anzahl, @Nullable BigDecimal prozent, DokumentFormatter formatter,
      boolean isDifferenz) {
    this(anzahl, prozent, formatter, isDifferenz, anzahl);
  }

  protected AnzahlMitProzent(@Nullable Long anzahl, @Nullable BigDecimal prozent, DokumentFormatter formatter,
      boolean isDifferenz, @Nullable Long prozentSignum) {
    this.anzahl = anzahl;
    this.prozent = prozent;
    this.anzahlFormatiert = isDifferenz
        ? formatter.formatStimmzahlDifferenz(anzahl)
        : formatter.formatStimmzahl(anzahl);
    this.prozentFormatiert = isDifferenz
        ? formatter.formatStimmanteilDifferenz(prozent, prozentSignum)
        : formatter.formatStimmanteil(prozent, anzahl);
  }

  public AnzahlMitProzent(DokumentFormatter formatter) {
    this(null, (Long) null, formatter);
  }

  /**
   * @return (anzahl * 100 / bezugsgroesse) als BigDecimal auf 20 Nachkommastellen
   */
  private static BigDecimal createProzent(@Nullable Long anzahl, @Nullable Long bezugsgroesse) {
    return (anzahl != null && bezugsgroesse != null) ? PercentUtil.percentGerundetNachkommastellenExact(bezugsgroesse, anzahl) : null;
  }

  public static AnzahlMitProzent createDifferenz(@Nullable Long anzahl, @Nullable Long bezugsgroesse,
      @Nullable Long anzahlVergleich, @Nullable Long bezugsgroesseVergleich, DokumentFormatter formatter) {

    return createDifferenz(anzahl, bezugsgroesse, anzahlVergleich, bezugsgroesseVergleich, formatter, true);
  }

  /**
   * Rechnerisch wie eine Differenz berechnet, die Formatierung aber nicht als Differenz
   */
  public static AnzahlMitProzent createDifferenzNormalFormatiert(@Nullable Long anzahl, @Nullable Long bezugsgroesse,
      @Nullable Long anzahlVergleich, @Nullable Long bezugsgroesseVergleich, DokumentFormatter formatter) {

    return createDifferenz(anzahl, bezugsgroesse, anzahlVergleich, bezugsgroesseVergleich, formatter, false);
  }

  private static AnzahlMitProzent createDifferenz(@Nullable Long anzahl, @Nullable Long bezugsgroesse,
      @Nullable Long anzahlVergleich, @Nullable Long bezugsgroesseVergleich, DokumentFormatter formatter,
      boolean isDifferenz) {
    Long differenz = subtractLongNull(anzahl, anzahlVergleich);
    BigDecimal percentDifference = PercentUtil.percentDifference(bezugsgroesse, anzahl, bezugsgroesseVergleich,
        anzahlVergleich);
    int percentDifferenceSignum = PercentUtil.percentDifferenceSignum(bezugsgroesse, anzahl, bezugsgroesseVergleich,
        anzahlVergleich);

    return new AnzahlMitProzent(differenz, percentDifference, formatter, isDifferenz,
        Long.valueOf(percentDifferenceSignum));
  }

  private static BigDecimal notNull(@Nullable BigDecimal value) {
    return value == null ? BigDecimal.ZERO : value;
  }
}
