
package de.ivu.elect.dokumente.ergebnis;

import static org.apache.commons.lang3.StringUtils.compareIgnoreCase;
import static org.apache.commons.lang3.StringUtils.leftPad;
import static org.apache.commons.lang3.StringUtils.length;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

import java.util.List;

import de.ivu.document.generator.template.annotations.DocumentComplexField;
import de.ivu.document.generator.template.annotations.DocumentSimpleField;
import de.ivu.elect.business.wahl.entity.WahlartErgebnisart;
import de.ivu.elect.dokumente.BaseElectContext;
import de.ivu.elect.dokumente.ElectDocument;
import de.ivu.elect.dokumente.wahl.UmgangWaehlerDocument;
import de.ivu.elect.dokumente.wahl.UmgangWahlberechtigteDocument;

public abstract class AbstractErgebnisTabellarischDocument<Z extends ErgebnisDocumentZeile> extends ElectDocument
    implements
      ErgebnisDocument,
      ErgebnisDocumentMitWahlverwaltungGebietInformation<ErgebnisDocumentGebietDocument> {

  private static final long serialVersionUID = 1L;

  @DocumentComplexField("Wahlart-Umgang-Wahlberechtigte") // ELECT-13015
  public final UmgangWahlberechtigteDocument wahlartUmgangWahlberechtigte;

  @DocumentComplexField("Wahlart-Umgang-Waehler") // ELECT-13015
  public final UmgangWaehlerDocument wahlartUmgangWaehler;

  @DocumentComplexField("Tabelle-Daten-Gebiet") // ELECT-8770
  public final ErgebnisDocumentDatenGebietDocument datenGebiet;

  @DocumentSimpleField("Tabelle-Daten-Art")
  public final ErgebnisDocumentDatenArt datenArt;

  @DocumentComplexField("Wahlkreis")
  public ErgebnisDocumentGebietDocument wahlkreis; // Oberbayern

  @DocumentComplexField("Stimmkreis")
  public ErgebnisDocumentGebietDocument stimmkreis; // 101 München-Hadern

  @DocumentComplexField("Wahlbereich")
  public ErgebnisDocumentGebietDocument wahlbereich;

  @DocumentComplexField("Bundesland")
  public ErgebnisDocumentGebietDocument bundesland; // Bayern

  @DocumentComplexField("Landkreis")
  public ErgebnisDocumentGebietDocument landkreis; // Kreisfreie Stadt

  @DocumentComplexField("Gemeindeverband")
  public ErgebnisDocumentGebietDocument gemeindeverband; // Bspw. Samtgemeinde (KOM-NI), Amt (KOM-BB, KOM-MV, KOM-SH)

  @DocumentComplexField("Gemeinde")
  public ErgebnisDocumentGebietDocument gemeinde; // Landeshauptstadt München

  @DocumentComplexField("Ortsbezirk")
  public ErgebnisDocumentGebietDocument ortsbezirk; // ELECT-13692

  @DocumentComplexField("Stadtbezirk")
  public ErgebnisDocumentGebietDocument stadtbezirk; // Laim

  @DocumentSimpleField("Stimmenart")
  public String stimmenart;

  @DocumentSimpleField("Seite-Mit-Unterschrift")
  public Boolean seiteMitUnterschrift;

  @DocumentSimpleField("Seite-Mit-Fortsetzung")
  public Boolean seiteMitFortsetzung;

  @DocumentSimpleField("Seite-Nummer")
  public String seitenNummer;

  @DocumentSimpleField("Seite-Nummer-Max")
  public String seitenNummerMaximal;

  @DocumentSimpleField("Teil-Nummer")
  public String teilNummer;

  @DocumentSimpleField("Teil-Nummer-Fortsetzung")
  public String teilNummerFortsetzung;

  @DocumentSimpleField("Teil-Nummer-Max")
  public String teilNummerMaximal;

  public final WahlartErgebnisart ergebnisart;

  @DocumentSimpleField("Ergebnisart-Name")
  public String ergebnisartName;

  @DocumentSimpleField("Ergebnisart-Ist-Vorlaeufig")
  public Boolean ergebnisartVorlaeufig;

  @DocumentSimpleField("Ergebnisart-Ist-Endgueltig")
  public Boolean ergebnisartEndgueltig;

  public final BaseElectContext baseElectContext;

  protected AbstractErgebnisTabellarischDocument(BaseElectContext baseElectContext, WahlartErgebnisart wahlartErgebnisart, ErgebnisDocumentDatenGebietDocument datenGebiet,
      ErgebnisDocumentDatenArt datenArt) {
    super(baseElectContext);

    this.baseElectContext = baseElectContext;

    this.wahlartUmgangWahlberechtigte = wahlartErgebnisart.isEndgueltig() ? this.wahlartUmgangWahlberechtigteEndgueltig : this.wahlartUmgangWahlberechtigteVorlaeufig;
    this.wahlartUmgangWaehler = wahlartErgebnisart.isEndgueltig() ? this.wahlartUmgangWaehlerEndgueltig : this.wahlartUmgangWaehlerVorlaeufig;

    this.datenGebiet = datenGebiet;
    this.datenArt = datenArt;

    this.wahlkreis = new ErgebnisDocumentGebietDocument();
    this.stimmkreis = new ErgebnisDocumentGebietDocument();
    this.wahlbereich = new ErgebnisDocumentGebietDocument();

    this.bundesland = new ErgebnisDocumentGebietDocument();
    this.landkreis = new ErgebnisDocumentGebietDocument();
    this.gemeindeverband = new ErgebnisDocumentGebietDocument();
    this.gemeinde = new ErgebnisDocumentGebietDocument();
    this.ortsbezirk = new ErgebnisDocumentGebietDocument();
    this.stadtbezirk = new ErgebnisDocumentGebietDocument();

    this.stimmenart = "";

    this.seiteMitUnterschrift = false;
    this.seiteMitFortsetzung = false;

    this.seitenNummer = "0";
    this.seitenNummerMaximal = "0";

    this.teilNummer = "0";
    this.teilNummerFortsetzung = "";
    this.teilNummerMaximal = "0";

    this.ergebnisart = wahlartErgebnisart;
    this.ergebnisartName = wahlartErgebnisart.getTechnicalName();
    this.ergebnisartVorlaeufig = wahlartErgebnisart.isVorlaeufig();
    this.ergebnisartEndgueltig = wahlartErgebnisart.isEndgueltig();
  }

  public abstract List<Z> getZeilen();

  public void addZeilen(List<Z> zeilen) {
    getZeilen().addAll(zeilen);
  }

  protected <T extends AbstractErgebnisTabellarischDocumentZeile> List<T> filterZeilenBerechenbar(List<T> zeilen) {
    return AbstractErgebnisTabellarischDocumentZeile.filterZeilenBerechenbar(zeilen);
  }

  protected <T extends AbstractErgebnisTabellarischDocument< ? >> T copyTo(T target) {
    target.wahlkreis = wahlkreis.copy();
    target.stimmkreis = stimmkreis.copy();
    target.wahlbereich = wahlbereich.copy();

    target.bundesland = bundesland.copy();
    target.landkreis = landkreis.copy();
    target.gemeindeverband = gemeindeverband.copy();
    target.gemeinde = gemeinde.copy();
    target.ortsbezirk = ortsbezirk.copy();
    target.stadtbezirk = stadtbezirk.copy();

    target.stimmenart = stimmenart;

    target.seiteMitUnterschrift = seiteMitUnterschrift;
    target.seiteMitFortsetzung = seiteMitFortsetzung;

    target.seitenNummer = seitenNummer;
    target.seitenNummerMaximal = seitenNummerMaximal;

    target.teilNummer = teilNummer;
    target.teilNummerFortsetzung = teilNummerFortsetzung;
    target.teilNummerMaximal = teilNummerMaximal;

    return target;
  }

  @Override
  public ErgebnisDocumentGebietDocument getWahlkreis() {
    return wahlkreis;
  }

  @Override
  public ErgebnisDocumentGebietDocument getStimmkreis() {
    return stimmkreis;
  }

  @Override
  public ErgebnisDocumentGebietDocument getWahlbereich() {
    return wahlbereich;
  }

  @Override
  public ErgebnisDocumentGebietDocument getBundesland() {
    return bundesland;
  }

  @Override
  public ErgebnisDocumentGebietDocument getLandkreis() {
    return landkreis;
  }

  @Override
  public ErgebnisDocumentGebietDocument getGemeindeverband() {
    return gemeindeverband;
  }

  @Override
  public ErgebnisDocumentGebietDocument getGemeinde() {
    return gemeinde;
  }

  @Override
  public ErgebnisDocumentGebietDocument getOrtsbezirk() {
    return ortsbezirk;
  }

  @Override
  public ErgebnisDocumentGebietDocument getStadtbezirk() {
    return stadtbezirk;
  }

  public boolean hasSeitenNummer(String another) {
    return compareNummerFormatted(seitenNummer, another) == 0;
  }

  public int compareBySeitenNummer(AbstractErgebnisTabellarischDocument< ? > another) {
    return compareNummerFormatted(seitenNummer, another.seitenNummer);
  }

  public boolean hasTeilNummer(String another) {
    return compareNummerFormatted(teilNummer, another) == 0;
  }

  public int compareByTeilNummer(AbstractErgebnisTabellarischDocument< ? > another) {
    return compareNummerFormatted(teilNummer, another.teilNummer);
  }

  // ELECTMUC-2848
  private int compareNummerFormatted(String one, String another) {
    int maxLengthFormatted = Math.max(length(one), length(another));

    return compareIgnoreCase(leftPad(trimToEmpty(one), maxLengthFormatted, "0"), leftPad(trimToEmpty(another), maxLengthFormatted, "0"));
  }
}
