
package de.ivu.elect.was.sitzberechnung.control;

import static java.util.stream.Collectors.toList;

import java.util.Collection;
import java.util.List;

import javax.inject.Inject;

import de.ivu.elect.business.ergebnis.boundary.SitzeFactory;
import de.ivu.elect.business.ergebnis.entity.ErgebnisLogEintrag;
import de.ivu.elect.business.ergebnis.entity.ErgebnisLogEintragArt;
import de.ivu.elect.business.ergebnis.entity.Gewaehlt;
import de.ivu.elect.business.ergebnis.entity.GewaehltStatus;
import de.ivu.elect.business.ergebnis.entity.Sitze;
import de.ivu.elect.business.ergebniskonflikt.control.util.ErgebnisKonfliktLoeser;
import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt;
import de.ivu.elect.business.sitzberechnung.entity.Sitzberechnungsergebnis;
import de.ivu.elect.jee.entity.customdata.EmptyCustomData;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.was.sitzberechnung.entity.AbstractElectSitzberechnungKandidatur;
import de.ivu.elect.was.sitzberechnung.entity.ElectSitzberechnungEntities;
import de.ivu.elect.was.sitzberechnung.entity.ElectSitzberechnungGebiet;
import de.ivu.elect.was.sitzberechnung.entity.ElectSitzberechnungGruppe;

public class ElectSitzberechnungsergebnisMapper extends AbstractElectSitzberechnungMapper {

  @Inject
  transient SitzeFactory sitzeFactory;

  @Inject
  transient Messages messages;

  public ElectSitzberechnungsergebnisMapper() {
    super();
  }

  public Sitzberechnungsergebnis mapIntern(ElectSitzberechnungContext sitzberechnungContext, ElectSitzberechnungEntities sitzberechnungEntities, ElectErgebnisKonfliktMapper ergebnisKonfliktMapper,
      de.ivu.elect.sitzberechnung.Sitzberechnungsergebnis sitzberechnungsergebnis) {
    List<ErgebnisKonflikt> ergebnisKonflikte = mapErgebnisKonflikte(sitzberechnungContext, sitzberechnungEntities, ergebnisKonfliktMapper, sitzberechnungsergebnis.getKonflikte());

    List<Sitze> sitze = mapSitze(sitzberechnungsergebnis.getSitze());

    List<Gewaehlt> gewaehlte = mapGewaehlte(sitzberechnungsergebnis.getGewaehlte());

    List<ErgebnisLogEintrag> ergebnisLogEintraege = mapErgebnisLogEintraege(sitzberechnungContext, sitzberechnungsergebnis.getLogEintraege());

    Sitzberechnungsergebnis result = new Sitzberechnungsergebnis(sitze, gewaehlte, ergebnisKonflikte, ergebnisLogEintraege, "", sitzberechnungsergebnis.getCustomData());
    result.getKonflikte().forEach(ergebnisKonflikt -> result.getKonfliktLoeserMap().put(ergebnisKonflikt, new ErgebnisKonfliktLoeser())); // Voraussetzung zur Verwendung des Variantenberechners (falls verwendet)...

    return result;
  }

  protected List<ErgebnisLogEintrag> mapErgebnisLogEintraege(ElectSitzberechnungContext sitzberechnungContext, List<de.ivu.elect.sitzberechnung.SitzberechnungLogeintrag> ergebnisLogEintraege) {
    return ergebnisLogEintraege.stream().map(this::mapErgebnisLogEintrag).collect(toList());
  }

  private ErgebnisLogEintrag mapErgebnisLogEintrag(de.ivu.elect.sitzberechnung.SitzberechnungLogeintrag ergebnisLogEintrag) {
    ErgebnisLogEintrag result = new ErgebnisLogEintrag();
    result.setErgebnisLogEintragArt(mapErgebnisLogEintragArt(ergebnisLogEintrag.getErgebnisLogEintragArt()));
    result.setText(messages.getMessageForMessageKey(ergebnisLogEintrag.getMessageKey(), ergebnisLogEintrag.getObjects()));

    return result;
  }

  protected ErgebnisLogEintragArt mapErgebnisLogEintragArt(de.ivu.elect.sitzberechnung.ErgebnisLogEintragArt ergebnisLogEintragArt) {
    try {
      return ErgebnisLogEintragArt.valueOf(ergebnisLogEintragArt.name());
    } catch (Exception ex) {
      throw new IllegalStateException("ErgebnisLogEintragArt unbekannt [ergebnisLogEintragArt = " + ergebnisLogEintragArt + "]", ex);
    }
  }

  private List<ErgebnisKonflikt> mapErgebnisKonflikte(ElectSitzberechnungContext sitzberechnungContext, ElectSitzberechnungEntities sitzberechnungEntities,
      ElectErgebnisKonfliktMapper ergebnisKonfliktMapper, Collection<de.ivu.elect.sitzberechnung.konflikt.ErgebnisKonflikt> ergebnisKonflikte) {
    return ergebnisKonflikte.stream().map(ergebnisKonflikt -> mapErgebnisKonflikt(sitzberechnungContext, sitzberechnungEntities, ergebnisKonfliktMapper, ergebnisKonflikt)).collect(toList());
  }

  private ErgebnisKonflikt mapErgebnisKonflikt(ElectSitzberechnungContext sitzberechnungContext, ElectSitzberechnungEntities sitzberechnungEntities, ElectErgebnisKonfliktMapper ergebnisKonfliktMapper,
      de.ivu.elect.sitzberechnung.konflikt.ErgebnisKonflikt ergebnisKonflikt) {
    if (ergebnisKonflikt instanceof de.ivu.elect.sitzberechnung.konflikt.AbstractErgebnisKonflikt) {
      Object ergebnisKonfliktPersistent = ((de.ivu.elect.sitzberechnung.konflikt.AbstractErgebnisKonflikt) ergebnisKonflikt).getErgebnisKonfliktPersistent();

      if (ergebnisKonfliktPersistent instanceof ErgebnisKonflikt) {
        return (ErgebnisKonflikt) ergebnisKonfliktPersistent;
      }
    }

    return ergebnisKonfliktMapper.mapIntern(sitzberechnungContext, sitzberechnungEntities, ergebnisKonflikt);
  }

  protected List<Sitze> mapSitze(List<de.ivu.elect.sitzberechnung.Sitze> sitze) {
    return sitze.stream().map(this::mapSitze).collect(toList());
  }

  private Sitze mapSitze(de.ivu.elect.sitzberechnung.Sitze sitze) {
    Sitze result = sitzeFactory.create();
    result.setAnzahl(sitze.getAnzahlSitze());
    result.setAnzahlAnspruch(sitze.getAnzahlSitzeAnspruch());
    result.setGebiet(((ElectSitzberechnungGebiet) sitze.getGebiet()).getEntity());
    result.setGruppe(((ElectSitzberechnungGruppe) sitze.getGruppe()).getEntity());

    return result;
  }

  protected List<Gewaehlt> mapGewaehlte(List<de.ivu.elect.sitzberechnung.Gewaehlt> gewaehlte) {
    return gewaehlte.stream().map(this::mapGewaehlt).collect(toList());
  }

  private Gewaehlt mapGewaehlt(de.ivu.elect.sitzberechnung.Gewaehlt gewaehlt) {
    Gewaehlt result = new Gewaehlt(EmptyCustomData.INSTANCE);
    result.setKandidatur(((AbstractElectSitzberechnungKandidatur< ? >) gewaehlt.getKandidatur()).getEntity());
    result.setGewaehltStatus(mapGewaehltStatus(gewaehlt.getGewaehltStatus()));
    result.setRang(gewaehlt.getRang());

    return result;
  }

  protected GewaehltStatus mapGewaehltStatus(de.ivu.elect.sitzberechnung.GewaehltStatus gewaehltStatus) {
    try {
      return GewaehltStatus.valueOf(gewaehltStatus.name());
    } catch (Exception ex) {
      throw new IllegalStateException("GewaehltStatus unbekannt [gewaehltStatus = " + gewaehltStatus + "]", ex);
    }
  }
}
