
package de.ivu.elect.dokumente;

import java.math.BigDecimal;
import java.util.ArrayDeque;
import java.util.Date;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import de.ivu.document.generator.template.BaseDocument;
import de.ivu.document.generator.template.annotations.DocumentComplexField;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.elect.business.benutzerverwaltung.entity.Benutzer;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.business.wahl.entity.Wahlgang;
import de.ivu.elect.business.wahl.entity.Wahltermin;

public class ElectDocument extends BaseDocument {

  private static final long serialVersionUID = 1L;

  @DocumentSimpleField("Aktuelles-Datum (Date-Objekt)")
  public final Date aktuellesDatumAlsDate;

  @DocumentSimpleField("Aktuelles-Datum-Formatiert (Standardformat)")
  public final String aktuellesDatum;

  @DocumentSimpleField("Aktuelles-Datum-Formatiert (Kurzformat)")
  public final String aktuellesDatumKurzFormat;

  @DocumentSimpleField("Aktuelles-Datum-Formatiert (Langformat)")
  public final String aktuellesDatumLangFormat;

  @DocumentSimpleField("Aktuelle-Uhrzeit")
  public final String aktuelleUhrzeit;

  @DocumentSimpleField("Aktuelle-Uhrzeit (mit Sekunden)")
  public final String aktuelleUhrzeitSekunden;

  @DocumentSimpleField("Aktueller-Wochentag (Name)")
  public final String aktuellerWochentagName;

  @DocumentSimpleField("Aktueller-Wochentag (Kürzel)")
  public final String aktuellerWochentagKuerzel;

  @DocumentSimpleField("Wahl-Name")
  public final String wahlName;

  @DocumentSimpleField("Wahl-Jahr")
  public final String wahlJahr;

  @DocumentSimpleField("Wahlart")
  public final String wahlart;

  @DocumentSimpleField("Wahlart (Schlüssel)")
  public final String wahlartSchluessel;

  @DocumentSimpleField("Wahlart (Kurzname)")
  public final String wahlartKurzname; // ELECT-8840

  @DocumentSimpleField("Wahlart (Kennzeichen)")
  public final String wahlartKennzeichen; // ELECT-9731

  @DocumentSimpleField("Quorum/Prozenthuerde")
  public final BigDecimal quorum;

  @DocumentSimpleField("Wahltermin (Date-Objekt)")
  public final Date wahlterminAlsDate;

  @DocumentSimpleField("Wahltermin-Formatiert (Standardformat)")
  public final String wahltermin;

  @DocumentSimpleField("Wahltermin-Formatiert (Kurzformat)")
  public final String wahlterminKurzFormat;

  @DocumentSimpleField("Wahltermin-Formatiert (Langformat)")
  public final String wahlterminLangFormat;

  // Soll dazu dienen, dass man in Dokumenten einen Platzhalter einfügen kann, der dann durch nichts ersetzt wird. Als Text für den Platzhalter kann man einen Kommentar in das Dokument schreiben.
  @DocumentSimpleField("Entwicklerkommentar: Dies ersetzen")
  public final String entwicklerkommentar = StringUtils.EMPTY;

  @DocumentComplexField("Anwender")
  public final BenutzerDokument anwender;

  @DocumentSimpleField("format")
  public final DokumentFormatter format;

  @DocumentSimpleField("counter")
  public final DokumentCounter counter;

  @DocumentSimpleField("Erster Wahlgang")
  public final boolean ersterWahlgang;

  @DocumentSimpleField("Stichwahl")
  public final boolean stichwahl;

  // ELECT-9097
  @DocumentSimpleField("Stichwahl-Moeglich")
  public final boolean stichwahlMoeglich;

  @DocumentSimpleField("Wiederholungswahl")
  public final boolean wiederholungswahl;

  @DocumentSimpleField("Verbundene Wahl")
  public final boolean verbundeneWahl;

  @DocumentSimpleField("erzeuge kleines Dokument zum Testen")
  public final boolean generateSmallDocumentForTest;

  @DocumentComplexField("Parameter")
  public final CustomParameterDokument parameter;

  @DocumentSimpleField("ParameterFormat")
  public final CustomParameterDokumentFormatter parameterFormat;

  @DocumentSimpleField("stichtag.tageVorWahl(1)")
  public final ElectDocumentStichtag stichtag;

  @DocumentComplexField("Systemgebietsebene")
  public final SystemGebietsebeneDokument systemGebietsebene;

  private final Map<String, String> map = new HashMap<>(); // ELECT-12760

  private final Deque<String> stack = new ArrayDeque<>(); // ELECT-12760

  public ElectDocument(BaseElectContext baseElectContext) {
    super();

    this.parameter = baseElectContext.getCustomParameterDokument();
    this.parameterFormat = new CustomParameterDokumentFormatter(this.parameter);

    Date now = new Date();
    this.aktuellesDatumAlsDate = now;
    this.aktuellesDatum = baseElectContext.formatDateMedium(now);
    this.aktuellesDatumKurzFormat = baseElectContext.formatDateShort(now);
    this.aktuellesDatumLangFormat = baseElectContext.formatDateLong(now);

    this.aktuelleUhrzeit = baseElectContext.formatTimeHHmm(now);
    this.aktuelleUhrzeitSekunden = baseElectContext.formatTimeHHmmss(now);

    this.aktuellerWochentagName = baseElectContext.formatDatePattern(now, "EEEE");
    this.aktuellerWochentagKuerzel = baseElectContext.formatDatePattern(now, "EEE");

    Wahl wahl = baseElectContext.getWahl();
    Date wahlterminDatum;

    if (wahl != null) {
      Wahlart wahlart = wahl.getWahlart();

      this.wahlName = wahl.getName();
      this.wahlJahr = String.valueOf(wahl.getWahljahr());

      this.wahlart = wahlart.getNameGui();
      this.wahlartSchluessel = wahlart.getName();
      this.wahlartKurzname = wahlart.getKurzname();
      this.wahlartKennzeichen = wahlart.getKennzeichen();

      this.quorum = wahl.getQuorumProzenthuerde();

      Wahltermin wahltermin = wahl.getWahltermin();
      Wahlgang wahlgang = wahl.getWahlgang();

      wahlterminDatum = wahltermin.getWahldatum();

      this.verbundeneWahl = wahltermin.getWahlsByWahltermin().size() > 1;
      this.ersterWahlgang = wahlgang.isErsterWahlgang();
      this.stichwahl = wahlgang.isStichwahl();
      this.stichwahlMoeglich = wahltermin.isStichwahlMoeglich();
      this.wiederholungswahl = wahlgang.isWiederholungswahl();
    } else {
      Wahltermin wahltermin = baseElectContext.getWahltermin();

      if (wahltermin != null) {
        this.wahlName = wahltermin.getName();
        this.wahlJahr = String.valueOf(wahltermin.getWahljahr());

        this.wahlart = "";
        this.wahlartSchluessel = wahltermin.getName();
        this.wahlartKurzname = wahltermin.getName();
        this.wahlartKennzeichen = "";

        this.quorum = null;

        wahlterminDatum = wahltermin.getWahldatum();

        this.verbundeneWahl = wahltermin.getWahlsByWahltermin().size() > 1;
        this.ersterWahlgang = !wahltermin.isStichwahltermin();
        this.stichwahl = wahltermin.isStichwahltermin();
        this.stichwahlMoeglich = wahltermin.isStichwahlMoeglich();
        this.wiederholungswahl = false;
      } else {
        this.wahlName = "";
        this.wahlJahr = "";

        this.wahlart = "";
        this.wahlartSchluessel = "";
        this.wahlartKurzname = "";
        this.wahlartKennzeichen = "";

        this.quorum = null;

        wahlterminDatum = now;

        this.verbundeneWahl = false;
        this.ersterWahlgang = false;
        this.stichwahl = false;
        this.stichwahlMoeglich = false;
        this.wiederholungswahl = false;
      }
    }

    this.wahlterminAlsDate = wahlterminDatum;
    this.wahltermin = baseElectContext.formatDateMedium(wahlterminDatum);
    this.wahlterminKurzFormat = baseElectContext.formatDateShort(wahlterminDatum);
    this.wahlterminLangFormat = baseElectContext.formatDateLong(wahlterminDatum);

    this.stichtag = new ElectDocumentStichtag(baseElectContext, wahlterminDatum);

    Benutzer benutzer = baseElectContext.getAnwender();

    if (benutzer == null) {
      this.anwender = BenutzerDokument.EMPTY_OBJECT;
    } else {
      this.anwender = new BenutzerDokument(benutzer);
    }

    this.format = new DokumentFormatter(baseElectContext.getLocale());
    this.counter = new DokumentCounter();
    this.generateSmallDocumentForTest = baseElectContext.isGenerateSmallDocumentForTest();
    this.systemGebietsebene = new SystemGebietsebeneDokument(baseElectContext);
  }

  protected Long sumNullToZero(Long one, Long another) {
    return fixNullToZero(one) + fixNullToZero(another);
  }

  protected Long fixNullToZero(Long value) {
    if (value == null) {
      return 0L;
    }

    return value;
  }

  public Map<String, String> getMap() {
    return map;
  }

  public Deque<String> getStack() {
    return stack;
  }

  public String addMap(String key, String value) {
    if (key != null) {
      map.put(key, value);
    }
    return "";
  }

  public String getMap(String key) {
    if (key == null) {
      return "";
    }
    String value = map.get(key);
    if (StringUtils.isBlank(value)) {
      return "";
    }
    return value;
  }

  public String pushStack(String value) {
    stack.addFirst(value);
    return "";
  }

  public String pollStack() {
    try {
      String result = stack.removeFirst();
      if (StringUtils.isBlank(result)) {
        return "";
      }
      return result;
    } catch (Exception e) {
      return "";
    }
  }

  public String peekStack() {
    try {
      String result = stack.peekFirst();
      if (StringUtils.isBlank(result)) {
        return "";
      }
      return result;
    } catch (Exception e) {
      return "";
    }
  }

}
