
package de.ivu.elect.business.stimmeingabe.control.plausi;

import java.util.Collection;

import javax.inject.Inject;

import de.ivu.elect.business.gebietsbaum.boundary.GebietDAO;
import de.ivu.elect.business.gebietsbaum.boundary.GebietsgruppierungDAO;
import de.ivu.elect.business.gebietsbaum.boundary.WahlverwaltungGebietInformationResolver;
import de.ivu.elect.business.stimmeingabe.control.StimmeingabePlausiBuilder;
import de.ivu.elect.business.stimmeingabe.entity.Ergebniseingang;
import de.ivu.elect.business.stimmeingabe.entity.Stimmeingabe;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeGruppeStimmen;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeGruppeStimmenErfassenModel;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeKopfzahl;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeKopfzahlErfassenModel;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeListenkandidaturStimmenErfassenModel;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiFehlerart;
import de.ivu.elect.business.stimmeingabe.entity.StimmeingabePlausiTyp;
import de.ivu.elect.business.wahl.entity.CommonWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;

public class EuwStimmeingabePlausiBuilder extends AbstractErgebniseingangPlausiBuilder implements StimmeingabePlausiBuilder {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient GebietDAO gebietDAO;

  @Inject
  private transient GebietsgruppierungDAO gebietsgruppierungDAO;

  @Inject
  private transient WahlverwaltungGebietInformationResolver wahlverwaltungGebietInformationResolver;

  @Inject
  private transient EuwKopfzahlPlausiBuilder euwKopfzahlPlausiBuilder;

  public EuwStimmeingabePlausiBuilder() {
    super();
  }

  @Override
  public boolean isApplicable(Wahl wahl) {
    return CommonWahlart.EUROPAWAHL.equalsWahlart(wahl);
  }

  @Override
  protected AbstractStimmeingabePlausiDefinitions getStimmeingabePlausiDefinitions(Ergebniseingang ergebniseingang) {
    return euwKopfzahlPlausiBuilder.getStimmeingabePlausiDefinitions(ergebniseingang);
  }

  @Override
  protected void fillStimmeingabePlausis(StimmeingabePlausiBuilderContext context, StimmeingabeKopfzahlErfassenModel kopfzahlErfassenModel,
      StimmeingabeGruppeStimmenErfassenModel gruppeStimmenErfassenModel, Collection<StimmeingabeListenkandidaturStimmenErfassenModel> listenkandidaturStimmenErfassenModels) {
    fillAllgemeinePlausis(context);

    fillKopfzahlPlausis(kopfzahlErfassenModel, context);

    fillGruppeStimmenPlausis(kopfzahlErfassenModel, gruppeStimmenErfassenModel, context);

    fillStimmeingabeAnzahlenUngleichStimmeingabeAnzahlenInAnderenErfassungsgebietenPlausis(kopfzahlErfassenModel, gruppeStimmenErfassenModel, context);
  }

  protected void fillKopfzahlPlausis(StimmeingabeKopfzahlErfassenModel model, StimmeingabePlausiBuilderContext context) {
    euwKopfzahlPlausiBuilder.fillKopfzahlPlausis(model, context);
  }

  private void fillGruppeStimmenPlausis(StimmeingabeKopfzahlErfassenModel kopfzahlErfassenModel, StimmeingabeGruppeStimmenErfassenModel gruppeStimmenErfassenModel,
      StimmeingabePlausiBuilderContext context) {
    fillGruppeStimmenKopfzahlenPlausis(kopfzahlErfassenModel, gruppeStimmenErfassenModel, context);
    fillGruppeStimmenGueltigeUndUngueltigePlausis(gruppeStimmenErfassenModel, context);
    fillGruppeStimmenVergleichVorlaeufigEndgueltigPlausis(gruppeStimmenErfassenModel, context);
  }

  private void fillGruppeStimmenKopfzahlenPlausis(StimmeingabeKopfzahlErfassenModel kopfzahlErfassenModel, StimmeingabeGruppeStimmenErfassenModel gruppeStimmenErfassenModel,
      StimmeingabePlausiBuilderContext context) {
    Stimmeingabe stimmeingabeGueltigeListenstimmen = gruppeStimmenErfassenModel.getStimmeingabeGruppeGueltigeListenstimmen().orElse(null);
    Stimmeingabe stimmeingabeUngueltigeListenstimmen = gruppeStimmenErfassenModel.getStimmeingabeGruppeUngueltigeListenstimmen().orElse(null);

    if (stimmeingabeGueltigeListenstimmen != null && stimmeingabeUngueltigeListenstimmen != null) {
      if (isWaehlerGesamtZuPlausibilisieren(kopfzahlErfassenModel)) {
        StimmeingabeKopfzahl waehlerGesamt = kopfzahlErfassenModel.getWaehlerGesamt();

        // Gültige + Ungültige = Wähler
        addPlausiKopfzahl(waehlerGesamt,
            new WaehlerGesamtAnzahlGleichGueltigeStimmenAnzahlPlusUngueltigeStimmenAnzahlPlausi(stimmeingabeGueltigeListenstimmen, stimmeingabeUngueltigeListenstimmen,
                findStimmeingabePlausiKonfigurationOrDefaults(context, StimmeingabePlausiTyp.WAEHLER_GESAMT_ANZAHL_GLEICH_GUELTIGE_LISTENSTIMMEN_ANZAHL_PLUS_UNGUELTIGE_LISTENSTIMMEN_ANZAHL,
                    StimmeingabePlausiFehlerart.ERROR),
                getMessages()),
            context);
      }

      // max. 5 % Ungültige
      addPlausi(stimmeingabeUngueltigeListenstimmen,
          new UngueltigeStimmenAnzahlKleinerGleichGueltigeStimmenAnzahlAnteilPlausi(stimmeingabeGueltigeListenstimmen,
              findStimmeingabePlausiKonfigurationOrDefaults(context, StimmeingabePlausiTyp.UNGUELTIGE_LISTENSTIMMEN_ANZAHL_KLEINER_GLEICH_GUELTIGE_LISTENSTIMMEN_ANZAHL_ANTEIL,
                  StimmeingabePlausiFehlerart.WARNING, new StimmeingabeAnzahlComparedToStimmeingabeAnzahlAnteilPlausiCustomData(0.05D)),
              getMessages()),
          context);
    }
  }

  private void fillGruppeStimmenGueltigeUndUngueltigePlausis(StimmeingabeGruppeStimmenErfassenModel gruppeStimmenErfassenModel, StimmeingabePlausiBuilderContext context) {
    if (gruppeStimmenErfassenModel.hasStimmenGruppeGueltige()) {
      StimmeingabeGruppeStimmen stimmeingabeGueltigeStimmen = gruppeStimmenErfassenModel.getStimmenGruppeGueltige();

      // Gültige > 0
      addPlausiListenstimme(stimmeingabeGueltigeStimmen, new StimmeingabeAnzahlGroesserAnzahlPlausi(StimmeingabeAnzahlReference.SYSTEM_GRUPPE_GUELTIGE_LISTENSTIMMEN,
          findStimmeingabePlausiKonfigurationOrDefaults(context, StimmeingabePlausiTyp.GUELTIGE_LISTENSTIMMEN_ANZAHL_GROESSER_NULL, StimmeingabePlausiFehlerart.ERROR), getMessages()), context);

      // Gültige = Summe aller Wahlvorschlag Listenstimmen
      addPlausiListenstimme(stimmeingabeGueltigeStimmen,
          new GueltigeStimmenAnzahlGleichGruppeStimmenAnzahlenSummePlausi(gruppeStimmenErfassenModel.getStimmeingabenPolitischeGruppen(),
              findStimmeingabePlausiKonfigurationOrDefaults(context, StimmeingabePlausiTyp.GUELTIGE_LISTENSTIMMEN_ANZAHL_GLEICH_GRUPPE_LISTENSTIMMEN_ANZAHLEN_SUMME, StimmeingabePlausiFehlerart.ERROR),
              getMessages()),
          context);
    }
  }

  protected void fillStimmeingabeAnzahlenUngleichStimmeingabeAnzahlenInAnderenErfassungsgebietenPlausis(StimmeingabeKopfzahlErfassenModel kopfzahlErfassenModel,
      StimmeingabeGruppeStimmenErfassenModel gruppeStimmenErfassenModel, StimmeingabePlausiBuilderContext context) {
    if (isWaehlerGesamtZuPlausibilisieren(kopfzahlErfassenModel) && kopfzahlErfassenModel.hasWaehlerGesamt() && !isBriefwahl(context) && !isSonderstimmbezirk(context)) {
      Stimmeingabe stimmeingabeWaehlerGesamt = kopfzahlErfassenModel.getWaehlerGesamt().getStimmeingabe();

      addPlausi(stimmeingabeWaehlerGesamt, // ELECTMUC-2452, ELECTKOM-308
          new EuwStimmeingabeAnzahlenUngleichStimmeingabeAnzahlenInAnderenErfassungsgebietenPlausi(context.getGebiet(), context.getErgebniseingang(), context.getWahlParameterLoader(), getGebietDAO(),
              getGebietsgruppierungDAO(), getErgebnisGueltigerEingangDAO(), getWahlverwaltungGebietInformationResolver(), getErgebniseingangEingabeHashCodeGenerator(),
              findStimmeingabePlausiKonfigurationOrDefaults(context, StimmeingabePlausiTyp.STIMMEINGABE_ANZAHLEN_UNGLEICH_STIMMEINGABE_ANZAHLEN_IN_ANDEREN_ERFASSUNGSGEBIETEN,
                  StimmeingabePlausiFehlerart.WARNING),
              getMessages()),
          context);
    }
  }

  protected GebietDAO getGebietDAO() {
    return gebietDAO;
  }

  protected GebietsgruppierungDAO getGebietsgruppierungDAO() {
    return gebietsgruppierungDAO;
  }

  protected WahlverwaltungGebietInformationResolver getWahlverwaltungGebietInformationResolver() {
    return wahlverwaltungGebietInformationResolver;
  }
}
