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

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

import javax.annotation.Nullable;

import de.ivu.elect.business.stimmeingabe.entity.StimmeingabeListenkandidaturStimmen;
import de.ivu.elect.business.wahl.entity.Wahl;

public abstract class AbstractStimmeingabeListenkandidaturStimmenGrouper implements StimmeingabeListenkandidaturStimmenGrouper {

  public AbstractStimmeingabeListenkandidaturStimmenGrouper() {
    super();
  }

  @Override
  public List<List<StimmeingabeListenkandidaturStimmen>> createGroupsOfStimmeingabenListenkandidaturStimmenIncludingPlatzhalter(Wahl wahl,
      @Nullable StimmeingabeListenkandidaturStimmen stimmeingabeListenkandidaturStimmenListenStimmen,
      List<StimmeingabeListenkandidaturStimmen> stimmeingabenListenkandidaturStimmenListenkandidaturStimmen) {
    List<List<StimmeingabeListenkandidaturStimmen>> result = new ArrayList<>();

    List<StimmeingabeListenkandidaturStimmen> stimmeingabenStimmen = new ArrayList<>();

    if (stimmeingabeListenkandidaturStimmenListenStimmen != null && isListeStimmenInBlockMitListenkandidaturStimmenDarstellen(wahl)) {
      stimmeingabenStimmen.add(stimmeingabeListenkandidaturStimmenListenStimmen);
    }

    stimmeingabenStimmen.addAll(stimmeingabenListenkandidaturStimmenListenkandidaturStimmen);

    int anzahlStimmeingaben = stimmeingabenStimmen.size();

    int fromIndex = 0;

    for (int spaltenGroesse : berechneGroesseDerSpaltenFuerStimmeingabenUndFuelleLetzteSpalte(wahl, anzahlStimmeingaben)) {
      int toIndex = fromIndex + spaltenGroesse;

      if (toIndex > anzahlStimmeingaben) {
        List<StimmeingabeListenkandidaturStimmen> spalte = new ArrayList<>(stimmeingabenStimmen.subList(fromIndex, anzahlStimmeingaben));

        for (int i = anzahlStimmeingaben; i < toIndex; i++) {
          spalte.add(StimmeingabeListenkandidaturStimmen.createPlatzhalter());
        }

        result.add(spalte);
      } else {
        result.add(new ArrayList<>(stimmeingabenStimmen.subList(fromIndex, toIndex)));
      }

      fromIndex += spaltenGroesse;
    }

    return result;
  }

  private List<Integer> berechneGroesseDerSpaltenFuerStimmeingabenUndFuelleLetzteSpalte(Wahl wahl, int anzahlStimmeingaben) {
    List<Integer> result = berechneGroesseDerSpaltenFuerStimmeingaben(wahl, anzahlStimmeingaben);

    fuelleLetzteSpalte(result);

    return result;
  }

  protected abstract List<Integer> berechneGroesseDerSpaltenFuerStimmeingaben(Wahl wahl, int anzahlStimmeingaben);

  private void fuelleLetzteSpalte(List<Integer> result) {
    if (result.size() <= 1) { // HINT: das Auffuellen dient nur dem Anpassen unterfuellter Spalten an restliche Spalten -- eine einzelne Spalte muss also nicht aufgefuellt werden
      return;
    }

    int indexLetzteSpalte = result.size() - 1;
    int sollGroesseLetzteSpalte = result.get(indexLetzteSpalte - 1);

    result.set(indexLetzteSpalte, Math.max(result.get(indexLetzteSpalte), sollGroesseLetzteSpalte));
  }
}
