
package de.ivu.elect.business.gruppe.boundary;

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

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

import javax.ejb.Stateless;
import javax.inject.Inject;

import de.ivu.elect.business.ergebnis.entity.NachErfassungsgebietStimmenSearchGebietsauswahl;
import de.ivu.elect.business.gebietsbaum.boundary.GebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.Svg;
import de.ivu.elect.business.gebietsbaum.entity.SvgLegendeKonfiguration;
import de.ivu.elect.business.gruppe.control.AbstractGruppeNachErfassungsgebietBuilder;
import de.ivu.elect.business.gruppe.control.GebietSvgBuilder;
import de.ivu.elect.business.gruppe.control.GebietSvgBuilderParameters;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.gruppe.entity.GruppeKumulierteStimmen;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.gruppe.entity.SvgAnzahlEinteilung;
import de.ivu.elect.business.gruppe.entity.SvgArtEinteilung;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.presentation.gruppe.table.AbstractGruppeKumulierteStimmenColumn;
import de.ivu.elect.presentation.gruppe.table.GruppeNachErfassungsgebietStimmenColumnBuilder;

@Stateless
public class GruppeNachErfassungsgebietSvgBuilder extends AbstractGruppeNachErfassungsgebietBuilder<Svg> {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient Messages messages;

  @Inject
  private transient GebietDAO gebietDAO;

  @Inject
  private transient GebietSvgBuilder gebietSvgBuilder;

  public GruppeNachErfassungsgebietSvgBuilder() {
    super();
  }

  @Override
  protected Svg buildInternal(GruppeNachErfassungsgebietStimmenSearchParameters searchParameters, List<GruppeKumulierteStimmen> searchResult,
      List<AbstractGruppeKumulierteStimmenColumn> darzustellendeWerte, GruppeNachErfassungsgebietStimmenColumnBuilder gruppeNachErfassungsgebietStimmenColumnBuilder) {
    if (darzustellendeWerte.size() != 1) {
      return new Svg(Collections.emptyList(), 1, 1);
    }

    AbstractGruppeKumulierteStimmenColumn wertFunktion = darzustellendeWerte.get(0);

    GebietSvgBuilderParameters parameters = new GebietSvgBuilderParameters() {

      @Override
      public NachErfassungsgebietStimmenSearchGebietsauswahl getGebietsauswahl() {
        return searchParameters.getGebietsauswahl();
      }

      @Override
      public long getWidthSvg() {
        return searchParameters.getChartGroesse().getWidthSvg();
      }

      @Override
      public long getHeightSvg() {
        return searchParameters.getChartGroesse().getHeightSvg();
      }

      @Override
      public boolean isProzentualeAngaben() {
        return GruppeNachErfassungsgebietSvgBuilder.this.isProzentualeAngaben(darzustellendeWerte);
      }

      @Override
      public SvgArtEinteilung getSvgArtEinteilung() {
        return searchParameters.getSvgArtEinteilung();
      }

      @Override
      public SvgLegendeKonfiguration getSvgLegendeKonfiguration() {
        return new SvgLegendeKonfiguration(bestimmeLegendeHeader(), searchParameters.getSvgLegendePositionHorizontal() * 0.01d, searchParameters.getSvgLegendePositionVertikal() * 0.01d);
      }

      private String bestimmeLegendeHeader() {

        if (isProzentualeAngaben()) {
          return messages.getMessageForMessageKey("gruppe.nach.gebiet.svg.legende.header.relativ");
        }
        return messages.getMessageForMessageKey("gruppe.nach.gebiet.svg.legende.header.absolut");
      }

      @Override
      public SvgAnzahlEinteilung getSvgAnzahlEinteilung() {
        return searchParameters.getSvgAnzahlEinteilung();
      }

      @Override
      public Function<Gebiet, String> getGebietGewinnerFarbeFunction() {

        return g -> {
          String farbe = "white";
          PolitischeGruppe pg = bestimmeGewinnerImGebiet(g, searchResult, wertFunktion);
          if (pg != null && pg.getFarbe() != null) {
            farbe = "#" + pg.getFarbe();
          }

          return farbe;
        };
      }

      @Override
      public Function<Gebiet, String> getGebietGewinnerNameFunction() {
        return g -> {
          String name = "?";
          PolitischeGruppe pg = bestimmeGewinnerImGebiet(g, searchResult, wertFunktion);
          if (pg != null && pg.getKurzname() != null) {
            name = pg.getKurzname();
          }

          return name;
        };
      }

      @Override
      public void sortGewinnerNamnen(List<String> gewinner) {
        List<String> gruppenNamen = searchParameters.getGruppen().stream().map(Gruppe::getKurzname).collect(toList());
        gewinner.sort((u, v) -> gruppenNamen.indexOf(u) - gruppenNamen.indexOf(v));

      }

      private PolitischeGruppe bestimmeGewinnerImGebiet(Gebiet gebiet, List<GruppeKumulierteStimmen> searchResult, AbstractGruppeKumulierteStimmenColumn wertFunktion) {

        PolitischeGruppe result = null;
        Long resultValue = null;
        for (GruppeKumulierteStimmen gruppeKumulierteStimmen : searchResult) {
          if (gebiet.equals(gruppeKumulierteStimmen.getGebiet()) && gruppeKumulierteStimmen.getGruppe() != null && gruppeKumulierteStimmen.getGruppe().isPolitischeGruppe()) {

            Long aktuell = (Long) wertFunktion.getDisplayValue(gruppeKumulierteStimmen);
            if (aktuell != null && aktuell > 0 && (resultValue == null || aktuell > resultValue)) {
              resultValue = aktuell;
              result = gruppeKumulierteStimmen.getGruppe().castTo(PolitischeGruppe.class).getEntity();
            }
          }
        }
        return result;
      }

      @Override
      public String getBasisFarbe() {
        Gruppe gruppe = bestimmeGruppe(searchResult);
        if (gruppe == null) {
          return null;
        }
        return gruppe.getFarbe();
      }

      private Gruppe bestimmeGruppe(List<GruppeKumulierteStimmen> searchResult) {
        Set<Gruppe> gruppen = searchResult.stream().map(GruppeKumulierteStimmen::getGruppe).collect(toSet());
        if (gruppen.size() == 1) {
          return gruppen.iterator().next();
        }

        return null;
      }

      @Override
      public Function<Gebiet, Double> getGebietValueFunction() {
        return g -> {

          for (GruppeKumulierteStimmen gruppeKumulierteStimmen : searchResult) {
            if (g.equals(gruppeKumulierteStimmen.getGebiet())) {
              Double displayValue = (Double) wertFunktion.getDisplayValue(gruppeKumulierteStimmen);
              if (displayValue != null) {
                return displayValue;
              }
              break;
            }
          }
          return null;
        };
      }
    };

    return gebietSvgBuilder.buildSvg(gebietDAO.attach(searchParameters.getGebietSelected()), parameters);
  }
}
