
package de.ivu.elect.business.gruppeimgebiet.control;

import java.util.List;

import javax.inject.Inject;
import javax.persistence.NoResultException;

import de.ivu.elect.business.ergebnis.control.StimmenPool;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.boundary.GruppeDAO;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.GruppeArt;
import de.ivu.elect.business.gruppe.entity.SystemGruppe;
import de.ivu.elect.business.gruppe.entity.SystemGruppeEigenschaften;
import de.ivu.elect.business.gruppeimgebiet.boundary.GruppeImGebietDAO;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;

public class GruppeImGebietUebrigeEinsortierer {

  @Inject
  private GruppeDAO gruppeDAO;

  @Inject
  GruppeImGebietDAO gruppeImGebietDAO;

  @Inject
  private SystemGruppeEigenschaften systemGruppeEigenschaften;

  public void sortiereUebrigeImGebietEinMitEinzelbewerbern(List<GruppeImGebiet> gruppenImGebietVorsortiert,
      Gebiet gebiet, List<GruppeImGebiet> irrelevante, StimmenPool vorperiodeStimmen) {
    sortiereUebrigeImGebietEin(gruppenImGebietVorsortiert, gebiet,
        GruppeImGebietEinzelkandidatenExportOption.IMMER_EXPORTIEREN, irrelevante, vorperiodeStimmen);
  }

  public void sortiereUebrigeImGebietEinOhneEinzelbewerbern(List<GruppeImGebiet> gruppenImGebietVorsortiert,
      Gebiet gebiet, List<GruppeImGebiet> irrelevante, StimmenPool vorperiodeStimmen) {
    sortiereUebrigeImGebietEin(gruppenImGebietVorsortiert, gebiet,
        GruppeImGebietEinzelkandidatenExportOption.NICHT_EXPORTIEREN, irrelevante, vorperiodeStimmen);
  }

  protected void sortiereUebrigeImGebietEin(List<GruppeImGebiet> gruppenImGebietVorsortiert, Gebiet gebiet,
      GruppeImGebietEinzelkandidatenExportOption option, List<GruppeImGebiet> irrelevante, StimmenPool vorperiodeStimmen) {

    GruppeImGebiet uebrigeImGebiet = holeUebrigeImGebiet(gebiet);

    sortiereUebrigeImGebietEin(gruppenImGebietVorsortiert, uebrigeImGebiet, option, irrelevante, vorperiodeStimmen);

  }

  protected GruppeImGebiet holeUebrigeImGebiet(Gebiet gebiet) {
    if (gebiet == null) {
      return null;
    }
    String schluesselUebrige = systemGruppeEigenschaften.getSchluessel(SystemGruppe.UEBRIGE);
    try {
      Gruppe gruppenUebrige = gruppeDAO.findByWahlAndSchluessel(gebiet.getWahl(), schluesselUebrige);
      return gruppeImGebietDAO.findByGruppeAndGebiet(gruppenUebrige, gebiet);
    } catch (NoResultException e) {
      return null;
    }
  }

  public void sortiereUebrigeImGebietEin(List<GruppeImGebiet> gruppenImGebietVorsortiert,
      GruppeImGebiet uebrigeImGebiet, GruppeImGebietEinzelkandidatenExportOption option,
      List<GruppeImGebiet> irrelevante,StimmenPool vorperiodeStimmen) {

    if (gruppenImGebietVorsortiert == null || uebrigeImGebiet == null) {
      return;
    }

    uebrigeImGebiet.setListenStimmenVorperiodeKumuliertZusatz(bestimmeAnzahlListenStimmenIrrelevante(irrelevante, vorperiodeStimmen),
        bestimmeListenStimmenVorperiodeVorhanden(irrelevante,vorperiodeStimmen));

    uebrigeImGebiet.setDirektStimmenVorperiodeKumuliertZusatz(bestimmeAnzahlDirektStimmenIrrelevante(irrelevante,vorperiodeStimmen),
        bestimmeDirektStimmenVorperiodeVorhanden(irrelevante,vorperiodeStimmen));

    List<GruppeImGebiet> einzelbewerberImGebiet = getEinzelbewerberInGebiet(uebrigeImGebiet.getGebiet());

    boolean uebrigeEnthaeltEinzelbewerber = isUebrigeEnthaeltEinzelbewerber(uebrigeImGebiet, option,
        einzelbewerberImGebiet);

    if (uebrigeEnthaeltEinzelbewerber || uebrigeImGebiet.isListenStimmenVorperiodeImGebietOderDarunterVorhanden(vorperiodeStimmen)
        || uebrigeImGebiet.isDirektStimmenVorperiodeImGebietOderDarunterVorhanden(vorperiodeStimmen)) {

      if (uebrigeEnthaeltEinzelbewerber) {

        boolean uebrigeEnthaeltDirektkandidateZugelassenOderUnbestimmt = existiertDirektkandidatZugelassenOderUnbestimmt(einzelbewerberImGebiet);

        uebrigeImGebiet.setDirektkandidatVorhandenAnzeigen(uebrigeEnthaeltDirektkandidateZugelassenOderUnbestimmt);

        // ELECT-6763 immer hinten dran...
//        if (uebrigeEnthaeltDirektkandidateZugelassenOderUnbestimmt) {
//          ordneEinNachGruppenMitWahlvorschlagZugelassenOderUnbestimmt(gruppenImGebietVorsortiert, uebrigeImGebiet);
//          return;
//        }

      }

      gruppenImGebietVorsortiert.add(uebrigeImGebiet);

    }
  }

  private boolean bestimmeListenStimmenVorperiodeVorhanden(List<GruppeImGebiet> irrelevante, StimmenPool vorperiodeStimmen) {
    for (GruppeImGebiet gruppeImGebiet : irrelevante) {
      if (gruppeImGebiet.isListenStimmenVorperiodeImGebietOderDarunterVorhanden(vorperiodeStimmen)) {
        return true;
      }
    }
    return false;
  }

  private boolean bestimmeDirektStimmenVorperiodeVorhanden(List<GruppeImGebiet> irrelevante, StimmenPool vorperiodeStimmen) {
    for (GruppeImGebiet gruppeImGebiet : irrelevante) {
      if (gruppeImGebiet.isDirektStimmenVorperiodeImGebietOderDarunterVorhanden(vorperiodeStimmen)) {
        return true;
      }
    }
    return false;
  }

  private Long bestimmeAnzahlListenStimmenIrrelevante(List<GruppeImGebiet> irrelevante, StimmenPool vorperiodeStimmen) {
    long result = 0;
    for (GruppeImGebiet gruppeImGebiet : irrelevante) {
      result += gruppeImGebiet.getAnzahlListenStimmenVorperiodeKumuliert(vorperiodeStimmen);
    }
    return result;
  }

  private Long bestimmeAnzahlDirektStimmenIrrelevante(List<GruppeImGebiet> irrelevante, StimmenPool vorperiodeStimmen) {
    long result = 0;
    for (GruppeImGebiet gruppeImGebiet : irrelevante) {
      result += gruppeImGebiet.getAnzahlDirektStimmenVorperiodeKumuliert(vorperiodeStimmen);
    }
    return result;
  }

  protected List<GruppeImGebiet> getEinzelbewerberInGebiet(Gebiet gebiet) {
    return gruppeImGebietDAO.findByGebietAndGruppeArt(gebiet, GruppeArt.EINZELBEWERBER);
  }

  protected boolean isUebrigeEnthaeltEinzelbewerber(GruppeImGebiet uebrigeImGebiet,
      GruppeImGebietEinzelkandidatenExportOption option, List<GruppeImGebiet> einzelbewerberImGebiet) {
    return !option.isEinzelbewerberAnzeigen(uebrigeImGebiet.getGebiet()) && !einzelbewerberImGebiet.isEmpty();
  }

  private boolean existiertDirektkandidatZugelassenOderUnbestimmt(List<GruppeImGebiet> einzelbewerberImGebiet) {
    for (GruppeImGebiet gruppeImGebiet : einzelbewerberImGebiet) {
      if (gruppeImGebiet.hatDirektkandidatZugelassenOderUnbestimmtInGebietshierarchie()) {
        return true;
      }
    }
    return false;
  }

  private void ordneEinNachGruppenMitWahlvorschlagZugelassenOderUnbestimmt(
      List<GruppeImGebiet> gruppenImGebietVorsortiert, GruppeImGebiet uebrigeImGebiet) {
    int index = 0;
    for (GruppeImGebiet gruppeImGebietVorsortiert : gruppenImGebietVorsortiert) {
      if (gruppeImGebietVorsortiert.isSystemGruppe()
          || hatGruppeImGbeietWahlvorschlagZugelassenOderUnbestimmt(gruppeImGebietVorsortiert)) {
        index++;
      } else {
        gruppenImGebietVorsortiert.add(index, uebrigeImGebiet);
        return;
      }
    }
    gruppenImGebietVorsortiert.add(uebrigeImGebiet);
  }

  protected boolean hatGruppeImGbeietWahlvorschlagZugelassenOderUnbestimmt(GruppeImGebiet gruppeImGebietVorsortiert) {
    return gruppeImGebietVorsortiert.hatWahlvorschlagZugelassenOderUnbestimmtInGebietshierarchie();
  }

}
