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

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

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

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietPolygon;
import de.ivu.elect.business.gebietsbaum.entity.GebietPolygonPoint;
import de.ivu.elect.business.gebietsbaum.entity.GebietPolygonPointArt;
import de.ivu.elect.business.gebietsbaum.entity.GebietPolygone;


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

@Stateless
public class GebietGeometrieEdit {

  @Inject
  GebietDAO gebietDAO;

  @Inject
  GebietPolygonPointDAO gebietPolygonPointDAO;


  public Map<Gebiet, GebietPolygone> getGebietPolygone(Collection<Gebiet> gebiete) {
    return gebiete.stream().collect(toMap(Function.identity(), this::getGebietPolygone));
  }


  public GebietPolygone getGebietPolygone(Gebiet gebietNotAttached) {
    Gebiet gebiet = gebietDAO.attach(gebietNotAttached);
    return erzeugePolygone(gebietPolygonPointDAO.findByGebietOrderByPosition(gebiet), gebiet);
  }

  private GebietPolygone erzeugePolygone(List<GebietPolygonPoint> gebietPolygonPoints, Gebiet gebiet) {
    return new GebietPolygone(gebiet, gebietPolygonPoints);
  }

  public Map<Gebiet, GebietPolygone> getNachbarGebietPolygone(Gebiet gebietNotAttached) {
    Gebiet gebiet = gebietDAO.attach(gebietNotAttached);
    Map<Gebiet, GebietPolygone> result = new HashMap<>();
    if (gebiet.hasUebergeordnetesGebiet()) {
      result.putAll(getUntergeordneteGebietPolygons(gebiet.getUebergeordnetesGebiet()));
      result.remove(gebiet);
    }
    return result;
  }

  public Map<Gebiet, GebietPolygone> getUntergeordneteGebietPolygons(Gebiet gebietNotAttached) {
    Gebiet gebiet = gebietDAO.attach(gebietNotAttached);
    Map<Gebiet, GebietPolygone> result = new HashMap<>();
    for (Gebiet kind : gebietDAO.findByUebergeordnetesGebiet(gebiet)) {
      kind.getGebietsart().getName(); // lazy
      result.put(kind, getGebietPolygone(kind));
      result.putAll(getUntergeordneteGebietPolygons(kind));
    }

    return result;
  }

  public void save(Gebiet gebietNotAttached, GebietPolygone gebietPolygone) {
    Gebiet gebiet = gebietDAO.attach(gebietNotAttached);

    for (GebietPolygonPoint gebietPolygonPoint : gebietPolygonPointDAO.findByGebietOrderByPosition(gebiet)) {
      gebietPolygonPointDAO.remove(gebietPolygonPoint);
    }
    long pos = 0;

    if (gebietPolygone.getMittelpunkt() != null) {
      gebietPolygone.getMittelpunkt().setPosition(pos++);
      gebietPolygone.getMittelpunkt().setGebiet(gebiet);
      gebietPolygonPointDAO.persist(gebietPolygone.getMittelpunkt());
    }

    for (GebietPolygon gebietPolygon : gebietPolygone.getPolygonList()) {
      boolean erster = true;
      for (GebietPolygonPoint gebietPolygonPoint : gebietPolygon.getGebietPolygonPointListReadOnly()) {
        if (erster) {
          erster = false;
          gebietPolygonPoint.setGebietPolygonPointArt(GebietPolygonPointArt.BEGINN);
        } else {
          gebietPolygonPoint.setGebietPolygonPointArt(GebietPolygonPointArt.PUNKT);
        }
        gebietPolygonPoint.setGebiet(gebiet);
        gebietPolygonPoint.setPosition(pos++);
        gebietPolygonPointDAO.persist(gebietPolygonPoint);
      }
    }
  }
}
