
package de.ivu.elect.was.exchange.wahl;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.gebietsbaum.boundary.GebietFactory;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietTK;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsart;
import de.ivu.elect.business.gebietsbaum.entity.NlGebietCustomData;
import de.ivu.elect.business.gebietsbaum.entity.NlGebietsart;
import de.ivu.elect.business.gruppe.boundary.PolitischeGruppeFactory;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.NlPolitischeGruppe;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.wahl.boundary.WahlFactory;
import de.ivu.elect.business.wahl.boundary.WahlterminFactory;
import de.ivu.elect.business.wahl.control.Wahldaten;
import de.ivu.elect.business.wahl.entity.NlWahlart;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlParameter;
import de.ivu.elect.business.wahl.entity.WahlParameterWerte;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.nl.eml.EmlWrapper;
import de.ivu.elect.nl.eml.XmlHelper;
import de.ivu.elect.nl.eml.readable.Eml110aWrapper;
import de.ivu.wahl.wus.oasis.eml.ElectionIdentifierStructure110A;
import de.ivu.wahl.wus.oasis.eml.kiesraad.Committee;
import de.ivu.wahl.wus.oasis.eml.kiesraad.CommitteeCategoryType;
import de.ivu.wahl.wus.oasis.eml.kiesraad.ElectionSubcategoryType;
import de.ivu.wahl.wus.oasis.eml.kiesraad.ObjectFactory;
import de.ivu.wahl.wus.oasis.eml.kiesraad.Region;
import de.ivu.wahl.wus.oasis.eml.kiesraad.RegionCategoryType;
import de.ivu.wahl.wus.oasis.eml.kiesraad.RegisteredParty;


import static de.ivu.elect.business.wahl.entity.WahlParameterWerte.DOKUMENT_PLATZHALTER_BUNDESLAND_NAME;
import static de.ivu.elect.business.wahl.entity.WahlParameterWerte.DOKUMENT_PLATZHALTER_GEMEINDE_NAME;
import static de.ivu.elect.business.wahl.entity.WahlParameterWerte.DOKUMENT_PLATZHALTER_GEMEINDE_NUMMER;
import static de.ivu.elect.business.wahl.entity.WahlParameterWerte.DOKUMENT_PLATZHALTER_WAHLBEHOERRDE_NAME;
import static de.ivu.elect.business.wahl.entity.WahlParameterWerte.DOKUMENT_PLATZHALTER_WAHLKREIS_NAME;
import static de.ivu.elect.business.wahl.entity.WahlParameterWerte.DOKUMENT_PLATZHALTER_WAHLKREIS_NUMMER;

public class Eml110Mapper {

  private static final Logger LOG = LoggerFactory.getLogger(Eml110Mapper.class);

  @Inject
  private transient WahlFactory wahlFactory;

  @Inject
  private transient WahlterminFactory wahlterminFactory;

  @Inject
  private transient NlWahlartEmlMapper nlWahlartEmlMapper;

  @Inject
  private transient GebietFactory gebietFactory;

  @Inject
  private transient NlGebietsartEmlMapper nlGebietsartEmlMapper;

  @Inject
  private transient PolitischeGruppeFactory politischeGruppeFactory;

  public Wahl mappeWahl(EmlWrapper emlWrapper) {
    Wahl wahl = wahlFactory.create();
    Eml110aWrapper eml110aWrapper = new Eml110aWrapper(emlWrapper.getContent());
    ElectionIdentifierStructure110A electionIdentifier110a = eml110aWrapper.getElectionIdentifier110a();
    wahl.setWahltermin(wahlterminFactory.create());
    if (electionIdentifier110a.getElectionDate() != null) {
      wahl.getWahltermin().setWahldatum(electionIdentifier110a.getElectionDate().toGregorianCalendar().getTime());
    }

    wahl.setName(electionIdentifier110a.getElectionName());
    wahl.setKennzeichen(electionIdentifier110a.getId());
    wahl.setWahlart(new Wahlart());
    if (eml110aWrapper.getElection().getPreferenceThreshold() != null) {
      wahl.setQuorumProzenthuerde(new BigDecimal(eml110aWrapper.getElection().getPreferenceThreshold().longValue()));
    }
    NlWahlart nlWahlart = nlWahlartEmlMapper.getWahlart(electionIdentifier110a.getElectionCategory(), electionIdentifier110a.getElectionSubcategory());
    setNlWahlart(wahl.getWahlart(), nlWahlart);

    return wahl;
  }

  public ElectionSubcategoryType getElectionSubcategory(EmlWrapper emlWrapper) {
    return new Eml110aWrapper(emlWrapper.getContent()).getElectionIdentifier110a().getElectionSubcategory();
  }

  public void setNlWahlart(Wahlart wahlart, NlWahlart nlWahlart) {
    wahlart.setName(nlWahlart.getWahlartName());
    wahlart.setKennzeichen(nlWahlart.getKennzeichen());
  }

  public EmlWrapper mappe(Wahldaten<Wahl, Gebiet> wahldaten, Gebiet gebiet) {

    EmlWrapper eml = EmlWrapper.createEmlNoCanonicalization("110a");
    Eml110aWrapper eml110 = new Eml110aWrapper(eml.getContent());

    eml.getEmlConfig().setPrettyPrint(true); // ELECTVAPP-984

    Wahl wahl = wahldaten.getWahl();
    ElectionIdentifierStructure110A electionIdentifier110a = eml110.getElectionIdentifier110a();
    mappeWahldaten(wahl, gebiet, wahldaten::getGebiete, electionIdentifier110a, false);

    // ELECTVAPP-967
    eml110.getElection().setPreferenceThreshold(BigInteger.valueOf(NlWahlart.valueOf(wahl).getPreferencialBarrierNumerator(gebiet.getAnzahlSitze())));

    if (gebiet.getAnzahlSitze() != null) {
      eml110.getElection().setNumberOfSeats(BigInteger.valueOf(gebiet.getAnzahlSitze()));
    }

    eml110.getElection().getContest().getContestIdentifier().setId(NlWahlart.valueOf(wahl).getEml110ContestIdentifier());


    mappeGebiete(eml110, wahldaten, gebiet);

    List<PolitischeGruppe> gruppenMitZugelassenenListen = wahldaten.getPolitischeGruppenZugelassenSortiertNachPositionAufGebiet(wahldaten.getWurzelgebiet());
    // ELECT-9943 nur PolitischeGruppen mit zugelassenen Listen exportieren (wenn Listen vorhanden)
    if (gruppenMitZugelassenenListen.isEmpty()) {
      mappeParteien(eml110, wahldaten.getPolitischeGruppen());
    } else {
      mappeParteien(eml110, gruppenMitZugelassenenListen);
    }

    return eml;
  }

  public void mappeWahldaten(Wahl wahl, Gebiet gebiet, Supplier<List<Gebiet>> alleGebiete, ElectionIdentifierStructure110A electionIdentifier110a, boolean skipNominationDate) {
    electionIdentifier110a.setElectionDate(XmlHelper.mappeDateTimeToCalendar(wahl.getWahldatum()));
    if (!skipNominationDate) {
      electionIdentifier110a.setNominationDate(XmlHelper.mappeDateTimeToCalendar(NlWahlart.getNominationDate(wahl)));
    }
    electionIdentifier110a.setElectionName(wahl.getName());
    electionIdentifier110a.setId(wahl.getKennzeichen());
    electionIdentifier110a.setElectionCategory(nlWahlartEmlMapper.bestimmeElectionCategory(wahl.getWahlart()));
    electionIdentifier110a.setElectionSubcategory(nlWahlartEmlMapper.bestimmeElectionSubcategory(wahl.getWahlart(), gebiet, alleGebiete));
  }

  private void mappeParteien(Eml110aWrapper eml110, List<PolitischeGruppe> politischeGruppen) {
    politischeGruppen.stream().filter(g -> !new NlPolitischeGruppe(g).isBlancoListe() /*ELECTVAPP-1509*/).sorted(this::compareParteien)
        .forEach(p -> eml110.addRegisteredParty
            (p.getName()));
  }

  private int compareParteien(PolitischeGruppe u, PolitischeGruppe v) {
    // Parteien in der Reihenfolge ihres numerischen Schlüssels exportieren (so wurden sie auch importiert)
    Long uLong = asLong(u.getSchluessel());
    Long vLong = asLong(v.getSchluessel());

    if (uLong != null && vLong != null) {
      return uLong.compareTo(vLong);
    }

    if (uLong == null) {
      if (vLong == null) {
        return 0;
      }
      return 1;
    }
    return -1;

  }

  @Nullable
  private Long asLong(String s) {
    if (StringUtils.isBlank(s)) {
      return null;
    }
    try {
      return Long.parseLong(s);
    } catch (Exception e) {
      return null;
    }
  }

  private void mappeGebiete(Eml110aWrapper eml110, Wahldaten<Wahl, Gebiet> wahldaten, Gebiet gebiet) {
    List<Gebiet> untergebiete = wahldaten.getGebiete().stream().filter(untergebiet -> untergebiet.isEqualOderUntergebietVon(gebiet)).collect(Collectors.toList());

    for (Gebiet untergebiet : untergebiete) {
      Short nummer = Short.valueOf(untergebiet.getNummer());
      RegionCategoryType type = nlGebietsartEmlMapper.mappeGebietsart(untergebiet.getGebietsart());
      String name = untergebiet.getName();
      Short uebergeordnetNummer = null;
      RegionCategoryType uebergeordnetType = null;
      if (untergebiet.getUebergeordnetesGebiet() != null && untergebiet.getUebergeordnetesGebiet().isEqualOderUntergebietVon(gebiet)) {
        uebergeordnetNummer = Short.valueOf(untergebiet.getUebergeordnetesGebiet().getNummer());
        uebergeordnetType = nlGebietsartEmlMapper.mappeGebietsart(untergebiet.getUebergeordnetesGebiet().getGebietsart());
      }
      Region region = eml110.addRegion(nummer, type, name, uebergeordnetNummer, uebergeordnetType);
      if (NlGebietsart.isCsb(untergebiet, untergebiete)) {
        Committee committee = new ObjectFactory().createCommittee();
        committee.setCommitteeCategory(CommitteeCategoryType.CSB);
        committee.setCommitteeName(untergebiet.getExterneId()); // https://support.elect-it.com/wiki/display/ELECT/Datenmodell+-+NL+spezifisches+Mapping
        region.getCommittee().add(committee);
      }

      region.setFrysianExportAllowed(NlGebietsart.from(untergebiet).isFrysian()); // ELECT-9671

      if (NlGebietsart.isHsb(untergebiet)) {
        Committee committee = new ObjectFactory().createCommittee();
        committee.setCommitteeCategory(CommitteeCategoryType.HSB);
        region.getCommittee().add(committee);
      }
      if (NlGebietsart.isPSB(untergebiet)) {
        Committee committee = new ObjectFactory().createCommittee();
        committee.setCommitteeCategory(CommitteeCategoryType.PSB);
        region.getCommittee().add(committee);
      }
    }
  }

  public List<String> getGebieteZurAuswahl(EmlWrapper emlWrapper, Predicate<NlGebietsart> nlGebietsartBeachten) {
    return new Eml110aWrapper(emlWrapper.getContent()).getRegions().stream().filter(r -> r.getRegionCategory() != null)
        .filter(region -> nlGebietsartBeachten.test(nlGebietsartEmlMapper.getNlGebietsart(region.getRegionCategory(), region.isFrysianExportAllowed()))).map(this::getName)
        .collect(Collectors.toList());
  }

  public List<Gebiet> mappeGebiete(EmlWrapper emlWrapper, Wahl wahl, @Nullable String nameOberstesGebiet, List<WahlParameter> wahlparameter) {
    List<Gebiet> alleGebiete = new ArrayList<>();
    List<Region> regions = new Eml110aWrapper(emlWrapper.getContent()).getRegions();

    NlWahlart nlWahlart = NlWahlart.valueOf(wahl.getWahlart());

    Map<GebietTK, Gebiet> gebieteMap = new HashMap<>();
    Map<NlGebietsart, Gebietsart> gebietsartMap = new EnumMap<>(NlGebietsart.class);
    Map<Region, Gebiet> gebieteNachRegion = new HashMap<>();
    Map<Gebiet, Region> regionenNachGebiet = new HashMap<>();
    Map<RegionCategoryType, AtomicLong> nummernGeneratorFuerGebietsart = new EnumMap<>(RegionCategoryType.class);

    Map<RegionCategoryType, Map<String, Boolean>> frysianMap = new EnumMap<>(RegionCategoryType.class);
    for (Region region : regions) {
      RegionCategoryType regionCategory = region.getRegionCategory();
      if (regionCategory != null) {
        Gebiet gebiet = gebietFactory.create();
        alleGebiete.add(gebiet);
        gebieteNachRegion.put(region, gebiet);
        regionenNachGebiet.put(gebiet, region);
        gebiet.setWahl(wahl);
        gebiet.setName(region.getRegionName());
        if (region.getRegionNumber() == null) {
          // das oberste Gebiet hat in alten EML-Dateien keine Nummer
          gebiet.setNummer(Long.toString(nummernGeneratorFuerGebietsart.computeIfAbsent(regionCategory, x -> new AtomicLong(0L)).incrementAndGet()));
        } else {
          gebiet.setNummer(region.getRegionNumber().toString());
        }

        NlGebietsart nlGebietsart = nlGebietsartEmlMapper.getNlGebietsart(regionCategory, region.isFrysianExportAllowed());
        gebiet.setGebietsart(gebietsartMap.computeIfAbsent(nlGebietsart, x -> nlGebietsartEmlMapper.mappeGebietsart(nlGebietsart)));
        gebieteMap.put(gebiet.getGebietTK(), gebiet);

        frysianMap.computeIfAbsent(regionCategory, x -> new HashMap<>()).put(gebiet.getNummer(), region.isFrysianExportAllowed());

        if (region.getCommittee() != null) {
          for (Committee committee : region.getCommittee()) {
            CommitteeCategoryType committeeCategory = committee.getCommitteeCategory();
            if (committeeCategory != null) {
              boolean customCsb = false;
              if (CommitteeCategoryType.CSB.equals(committeeCategory)) {
                customCsb = true;
                String committeeName = committee.getCommitteeName();
                if (StringUtils.isBlank(committeeName)) {
                  committeeName = gebiet.getName();
                }
                gebiet.setExterneId(committeeName); // Name CSB https://support.elect-it.com/wiki/display/ELECT/Datenmodell+-+NL+spezifisches+Mapping
              }
              // dirty switch - nicht wichtig nur Logging
              switch (committeeCategory) {
                case CSB :
                  if (!nlGebietsart.isCSB(nlWahlart) && !customCsb) {
                    LOG.warn("NlGebietsart: " + nlGebietsart + " in NlWahlart: " + nlWahlart + " nicht CSB, Gebiet: " + gebiet.getName() + "; " + gebiet.getNummer() + ", " + gebiet);
                  }
                  break;
                case HSB :
                  if (!nlGebietsart.isHSB(nlWahlart)) {
                    LOG.warn("NlGebietsart: " + nlGebietsart + " in NlWahlart: " + nlWahlart + " nicht HSB, Gebiet: " + gebiet.getName() + "; " + gebiet.getNummer() + ", " + gebiet);
                  }
                  break;
                case PSB :
                case PROV_SB :
                  if (!nlGebietsart.isPSB(nlWahlart)) {
                    LOG.warn("NlGebietsart: " + nlGebietsart + " in NlWahlart: " + nlWahlart + " nicht PSB, Gebiet: " + gebiet.getName() + "; " + gebiet.getNummer() + ", " + gebiet);
                  }
                  break;
                default :
                  LOG.warn("Unbekannte committeeCategory: " + committeeCategory + ", Gebiet: " + gebiet.getName() + "; " + gebiet.getNummer() + ", " + gebiet);
              }
            }
          }
        }
      }
    }

    for (Region region : regions) {
      RegionCategoryType superiorRegionCategory = region.getSuperiorRegionCategory();
      Short superiorRegionNumber = region.getSuperiorRegionNumber();
      if (superiorRegionCategory != null) {
        Gebiet gebiet = gebieteNachRegion.get(region);
        if (gebiet != null) {

          String parentNummer;
          if (superiorRegionNumber == null) {
            AtomicLong genericNummer = nummernGeneratorFuerGebietsart.get(superiorRegionCategory);
            if (genericNummer == null) {
              continue;
            }
            parentNummer = Long.toString(genericNummer.get());
          } else {
            parentNummer = superiorRegionNumber.toString();
          }

          NlGebietsart nlGebietsart = nlGebietsartEmlMapper.getNlGebietsart(superiorRegionCategory,
              frysianMap.getOrDefault(superiorRegionCategory, Collections.emptyMap()).getOrDefault(parentNummer, false));
          Gebietsart parentGebietsart = gebietsartMap.computeIfAbsent(nlGebietsart, x -> nlGebietsartEmlMapper.mappeGebietsart(nlGebietsart));

          GebietTK parentTk = new GebietTK(parentNummer, parentGebietsart.getGebietsartTK());
          gebiet.setUebergeordnetesGebiet(gebieteMap.get(parentTk));
        }
      }
    }

    List<Gebiet> result = filterAusgewaehltesGebiet(alleGebiete, nameOberstesGebiet, wahlparameter, regionenNachGebiet);
    if (new Eml110aWrapper(emlWrapper.getContent()).getElection().getNumberOfSeats() != null) {
      List<Gebiet> oberstesGebiete = result.stream().filter(g -> !g.hasUebergeordnetesGebiet()).collect(Collectors.toList());
      if (oberstesGebiete.size() == 1) {
        // Die Anzahl der Sitze erstmal an das oberste Gebiet
        // später an die Wahlgebiete: de.ivu.elect.business.wahl.boundary.NlWahlImportHelper.postCreateGebiete
        Gebiet oberstesGebiet = oberstesGebiete.iterator().next();
        oberstesGebiet.setAnzahlSitze(new Eml110aWrapper(emlWrapper.getContent()).getElection().getNumberOfSeats().longValue());
      }
    }
    return result;
  }

  private List<Gebiet> filterAusgewaehltesGebiet(List<Gebiet> alleGebiete, @Nullable String nameOberstesGebiet, List<WahlParameter> wahlparameterList, Map<Gebiet, Region> regionenNachGebiet) {
    if (StringUtils.isBlank(nameOberstesGebiet)) {
      return alleGebiete;
    }

    Gebiet oberstesGebiet = findeGebiet(alleGebiete, nameOberstesGebiet, regionenNachGebiet);

    if (oberstesGebiet == null) {
      throw new IllegalArgumentException("Gebiet nicht gefunden: " + nameOberstesGebiet);
    }

    Wahl wahl = oberstesGebiet.getWahl();

    boolean wahlkreisGesetzt = false; // ELECT-9783
    for (Gebiet gebiet : alleGebiete) {
      // ELECT-9687

      if (NlGebietsart.from(gebiet).isKieskring() && gebiet.isInGebietshierarchieUebergeordnetesGebietVon(oberstesGebiet)) {
        addWahlparameter(wahlparameterList, wahl, gebiet, DOKUMENT_PLATZHALTER_WAHLKREIS_NAME, DOKUMENT_PLATZHALTER_WAHLKREIS_NUMMER);
        wahlkreisGesetzt = true;
      }
      // ELECT-9747
      if (NlGebietsart.from(gebiet).isProvinz() && gebiet.isInGebietshierarchieUebergeordnetesGebietVon(oberstesGebiet)) {
        addWahlparameter(wahlparameterList, wahl, gebiet, DOKUMENT_PLATZHALTER_BUNDESLAND_NAME, null);
      }
      if (NlGebietsart.from(gebiet).isGemeinde() && gebiet.isInGebietshierarchieUebergeordnetesGebietVon(oberstesGebiet)) {
        addWahlparameter(wahlparameterList, wahl, gebiet, DOKUMENT_PLATZHALTER_GEMEINDE_NAME, DOKUMENT_PLATZHALTER_GEMEINDE_NUMMER);
      }
    }

    for (Gebiet gebiet : alleGebiete) {
      if (NlGebietsart.isCsb(gebiet, alleGebiete)) {
        addWahlparameter(wahlparameterList, wahl, gebiet, DOKUMENT_PLATZHALTER_WAHLBEHOERRDE_NAME, null);
        if (!wahlkreisGesetzt /* ELECT-9783 in den Wahlkreis den Gemeindenamen setzen, wenn nicht bereits gesetzt */) {
          addWahlparameter(wahlparameterList, wahl, gebiet, DOKUMENT_PLATZHALTER_WAHLKREIS_NAME, DOKUMENT_PLATZHALTER_WAHLKREIS_NUMMER);
        }
      }
    }


    addMasterElectionTree(oberstesGebiet, oberstesGebiet.getUebergeordnetesGebiet());


    oberstesGebiet.setUebergeordnetesGebiet(null); // neues Wurzelgebiet...

    return alleGebiete.stream().filter(gebiet -> gebiet.isInGebietshierarchieUntergeordnetesGebietVon(oberstesGebiet)).collect(Collectors.toCollection(() -> new ArrayList<>(alleGebiete.size())));
  }

  private void addMasterElectionTree(Gebiet gebiet, Gebiet uebergeordnetesGebiet) {
    if (uebergeordnetesGebiet==null){
      return;
    }
    gebiet.getCustomData(NlGebietCustomData.class).addUebergeornetesGebietInMasterElectionTree(uebergeordnetesGebiet);
    addMasterElectionTree(gebiet, uebergeordnetesGebiet.getUebergeordnetesGebiet());
  }

  private void addWahlparameter(List<WahlParameter> wahlparameterList, Wahl wahl, Gebiet gebiet, WahlParameterWerte dokumentPlatzhalterName, @Nullable WahlParameterWerte dokumentPlatzhalterNummer) {
    WahlParameter parameterName = new WahlParameter();
    parameterName.setWahl(wahl);
    parameterName.setSchluessel(dokumentPlatzhalterName.getKey());
    parameterName.setWert(gebiet.getName());
    wahlparameterList.add(parameterName);

    if (dokumentPlatzhalterNummer != null) {
      WahlParameter parameterNummer = new WahlParameter();
      parameterNummer.setWahl(wahl);
      parameterNummer.setSchluessel(dokumentPlatzhalterNummer.getKey());
      parameterNummer.setWert(gebiet.getNummer());
      wahlparameterList.add(parameterNummer);
    }
  }

  @Nullable
  private Gebiet findeGebiet(List<Gebiet> result, String nameOberstesGebiet, Map<Gebiet, Region> regionenNachGebiet) {
    for (Gebiet gebiet : result) {
      Region region = regionenNachGebiet.get(gebiet);
      if (nameOberstesGebiet.equals(getName(region))) {
        return gebiet;
      }
    }
    return null;
  }

  private String getName(Region region) {
    if (region == null) {
      return "";
    }

    return region.getRegionName() + "|" + region.getRegionCategory().name();
  }

  public List<Gruppe> mappeGruppen(EmlWrapper emlWrapper, Wahl wahl) {
    List<Gruppe> result = new ArrayList<>();
    long position = 1;
    for (RegisteredParty registeredParty : new Eml110aWrapper(emlWrapper.getContent()).getRegisteredParties()) {
      PolitischeGruppe politischeGruppe = politischeGruppeFactory.create();
      result.add(politischeGruppe);

      NlPolitischeGruppe nlPolitischeGruppe = new NlPolitischeGruppe(politischeGruppe);
      nlPolitischeGruppe.setWahl(wahl);
      nlPolitischeGruppe.setGruppeArt(NlPolitischeGruppe.GRUPPE_ART_DEFAULT);
      nlPolitischeGruppe.setName(registeredParty.getRegisteredAppellation());
      nlPolitischeGruppe.setRelativePosition(position);
      nlPolitischeGruppe.setVorgegebenePosition(position);

      position++;
    }

    return result;
  }
}
