
package de.ivu.elect.dokumente.ergebnis;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.gebietsbaum.boundary.WahlverwaltungGebietInformation;
import de.ivu.elect.business.wahl.entity.WahlartErgebnisart;
import de.ivu.elect.dokumente.BaseElectContext;

public abstract class AbstractErgebnisTabellarischDocumentCreator<D extends AbstractErgebnisTabellarischDocument<Z>, Z extends AbstractErgebnisTabellarischDocumentZeile> {

  protected static final Logger LOG = LoggerFactory.getLogger(AbstractErgebnisTabellarischDocumentCreator.class);

  public AbstractErgebnisTabellarischDocumentCreator() {
    super();
  }

  public D createSummenDocumentFuerDatenArtUrnenwahl(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, List<Z> zeilenInDatenGebiet) {
    return createSummenDocumentFuerDatenArt(baseElectContext, ergebnisart, datenGebiet, ErgebnisDocumentDatenArt.URNENWAHL, zeilenInDatenGebiet);
  }

  public D createSummenDocumentFuerDatenArtBriefwahl(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, List<Z> zeilenInDatenGebiet) {
    return createSummenDocumentFuerDatenArt(baseElectContext, ergebnisart, datenGebiet, ErgebnisDocumentDatenArt.BRIEFWAHL, zeilenInDatenGebiet);
  }

  public D createSummenDocumentFuerDatenArtGesamt(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, List<Z> zeilenInDatenGebiet) {
    return createSummenDocumentFuerDatenArt(baseElectContext, ergebnisart, datenGebiet, ErgebnisDocumentDatenArt.GESAMT, zeilenInDatenGebiet);
  }

  private D createSummenDocumentFuerDatenArt(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, ErgebnisDocumentDatenArt datenArt,
      List<Z> zeilenInDatenGebiet) {
    D result = createDocumentFuerDatenArt(baseElectContext, ergebnisart, datenGebiet, datenArt, zeilenInDatenGebiet);
    fillInSummenDocument(result);

    return result;
  }

  protected void fillInSummenDocument(D document) {
    document.datenGebiet.name = ErgebnisDocumentDatenGebietDocument.PSEUDO_GEMEINDE_GESAMT_NAME;
    document.datenGebiet.nummer = ErgebnisDocumentDatenGebietDocument.PSEUDO_GEMEINDE_GESAMT_NUMMER;
    document.datenGebiet.nummerFormatiert = ErgebnisDocumentDatenGebietDocument.PSEUDO_GEMEINDE_GESAMT_NUMMER;
    document.datenGebiet.isPseudoGemeindeGesamt = true;

    document.gemeindeverband.name = document.datenGebiet.name;
    document.gemeindeverband.nummer = document.datenGebiet.nummer;
    document.gemeindeverband.nummerFormatiert = document.datenGebiet.nummerFormatiert;

    document.gemeinde.name = document.datenGebiet.name;
    document.gemeinde.nummer = document.datenGebiet.nummer;
    document.gemeinde.nummerFormatiert = document.datenGebiet.nummerFormatiert;
  }

  public D createDocumentFuerDatenArtUrnenwahl(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, List<Z> zeilenInDatenGebiet) {
    return createDocumentFuerDatenArt(baseElectContext, ergebnisart, datenGebiet, ErgebnisDocumentDatenArt.URNENWAHL, zeilenInDatenGebiet);
  }

  public D createDocumentFuerDatenArtBriefwahl(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, List<Z> zeilenInDatenGebiet) {
    return createDocumentFuerDatenArt(baseElectContext, ergebnisart, datenGebiet, ErgebnisDocumentDatenArt.BRIEFWAHL, zeilenInDatenGebiet);
  }

  public D createDocumentFuerDatenArtGesamt(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, List<Z> zeilenInDatenGebiet) {
    return createDocumentFuerDatenArt(baseElectContext, ergebnisart, datenGebiet, ErgebnisDocumentDatenArt.GESAMT, zeilenInDatenGebiet);
  }

  private D createDocumentFuerDatenArt(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, ErgebnisDocumentDatenArt datenArt,
      List<Z> zeilenInDatenGebiet) {
    return createDocument(baseElectContext, ergebnisart, datenGebiet, datenArt, collectZeilenFuerDatenArt(datenArt, zeilenInDatenGebiet));
  }

  protected D createDocument(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, ErgebnisDocumentDatenArt datenArt,
      List<Z> zeilenInDatenGebietFuerDatenArt) {
    for (Z zeile : zeilenInDatenGebietFuerDatenArt) {
      zeile.nummer = (long) (1 + zeilenInDatenGebietFuerDatenArt.indexOf(zeile));
    }

    D result = createDocument(baseElectContext, ergebnisart, datenGebiet, datenArt);
    result.stimmenart = datenArt.getName();

    // ELECT-9400
    result.datenGebiet.isErgebniseingabestatusKomplettEingabeBeendet = true;
    result.datenGebiet.isErgebniseingabestatusKomplettGesperrt = true;
    result.datenGebiet.isErgebniseingabestatusKomplettAbgeschlossen = true;
    result.datenGebiet.isErgebniseingabestatusKomplettFreigegeben = true;
    result.datenGebiet.isErgebniseingabestatusKomplettAusbleibend = true;

    for (Z zeile : zeilenInDatenGebietFuerDatenArt) {
      result.datenGebiet.isErgebniseingabestatusKomplettEingabeBeendet &= zeile.wahlbezirk.isErgebniseingabestatusEingabeBeendet;
      result.datenGebiet.isErgebniseingabestatusKomplettGesperrt &= zeile.wahlbezirk.isErgebniseingabestatusGesperrt;
      result.datenGebiet.isErgebniseingabestatusKomplettAbgeschlossen &= zeile.wahlbezirk.isErgebniseingabestatusAbgeschlossen;
      result.datenGebiet.isErgebniseingabestatusKomplettFreigegeben &= zeile.wahlbezirk.isErgebniseingabestatusFreigegeben;
      result.datenGebiet.isErgebniseingabestatusKomplettAusbleibend &= zeile.wahlbezirk.isErgebniseingabestatusAusbleibend;
    }

    result.addZeilen(zeilenInDatenGebietFuerDatenArt);

    if (zeilenInDatenGebietFuerDatenArt.isEmpty()) {
      LOG.warn("Keine Daten [datenGebiet = " + datenGebiet + ", datenArt = " + datenArt);
    } else {
      fillInDocument(result, zeilenInDatenGebietFuerDatenArt.get(0), datenArt);
    }

    return result;
  }

  protected abstract D createDocument(BaseElectContext baseElectContext, WahlartErgebnisart ergebnisart, WahlverwaltungGebietInformation datenGebiet, ErgebnisDocumentDatenArt datenArt);

  protected void fillInDocument(D document, Z template, ErgebnisDocumentDatenArt datenArt) {
    fillInDocumentBasisinformationen(document, template, datenArt);
  }

  protected void fillInDocumentBasisinformationen(AbstractErgebnisTabellarischDocument< ? > document, AbstractErgebnisTabellarischDocumentZeile template, ErgebnisDocumentDatenArt datenArt) {
    document.wahlkreis = template.wahlkreis.copy();
    document.stimmkreis = template.stimmkreis.copy();
    document.wahlbereich = template.wahlbereich.copy();

    document.bundesland = template.bundesland.copy();
    document.landkreis = template.landkreis.copy();
    document.gemeindeverband = template.gemeindeverband.copy();
    document.gemeinde = template.gemeinde.copy();

    document.stimmenart = datenArt.getName();
  }

  protected List<Z> collectZeilenFuerDatenArt(ErgebnisDocumentDatenArt datenArt, List<Z> zeilen) {
    if (ErgebnisDocumentDatenArt.GESAMT.equals(datenArt)) {
      return zeilen;
    }

    List<Z> result = new ArrayList<>();

    for (Z zeile : zeilen) {
      if (datenArt.equals(zeile.datenArt)) {
        result.add(zeile);
      }
    }

    return result;
  }
}
