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

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nullable;

public class GebietPolygon implements Serializable {

  private static final long serialVersionUID = 1L;

  private final List<GebietPolygonPoint> gebietPolygonPointList = new ArrayList<>();

  public List<GebietPolygonPoint> getGebietPolygonPointListReadOnly() {
    return Collections.unmodifiableList(gebietPolygonPointList);
  }

  public GebietPolygon add(GebietPolygonPoint gebietPolygonPoint) {
    gebietPolygonPointList.add(gebietPolygonPoint);
    nachfolgerMap = null;
    vorgaengerMap = null;
    return this;
  }

  public GebietPolygon remove(GebietPolygonPoint gebietPolygonPoint) {
    gebietPolygonPointList.remove(gebietPolygonPoint);
    nachfolgerMap = null;
    vorgaengerMap = null;
    return this;
  }

  public GebietPolygon() {
    super();
  }

  public int getAnzahlPunkte() {
    return gebietPolygonPointList.size();
  }

  public GebietPolygon(GebietPolygon toCopy) {
    for (GebietPolygonPoint gebietPolygonPoint : toCopy.getGebietPolygonPointListReadOnly()) {
      GebietPolygonPoint copy = new GebietPolygonPoint();
      gebietPolygonPoint.copyEntityAttributesUsingSetter(copy);
      add(copy);
    }
  }

  private transient Map<GebietPolygonPoint, GebietPolygonPoint> nachfolgerMap = null;

  private transient Map<GebietPolygonPoint, GebietPolygonPoint> vorgaengerMap = null;

  @Nullable
  public GebietPolygonPoint getNachfolger(GebietPolygonPoint vorgaenger) {

    if (nachfolgerMap == null) {
      erzeugeVorgaengerNachfolgerMaps();
    }

    return nachfolgerMap.get(vorgaenger);

  }

  @Nullable
  public GebietPolygonPoint getVorgaenger(GebietPolygonPoint nachfolger) {

    if (vorgaengerMap == null) {
      erzeugeVorgaengerNachfolgerMaps();
    }

    return vorgaengerMap.get(nachfolger);

  }

  private void erzeugeVorgaengerNachfolgerMaps() {
    gebietPolygonPointList.sort(Comparator.comparing(GebietPolygonPoint::getPosition));

    nachfolgerMap = new HashMap<>();
    vorgaengerMap = new HashMap<>();
    GebietPolygonPoint vorheriger = null;
    GebietPolygonPoint erster = null;
    GebietPolygonPoint letzter = null;
    for (GebietPolygonPoint gebietPolygonPoint : getGebietPolygonPointListReadOnly()) {
      if (gebietPolygonPoint.getGebietPolygonPointArt().isTeilDesPolygons()) {
        if (erster == null) {
          erster = gebietPolygonPoint;
        }
        if (vorheriger != null) {
          vorgaengerMap.put(gebietPolygonPoint, vorheriger);
          nachfolgerMap.put(vorheriger, gebietPolygonPoint);
        }
        letzter = gebietPolygonPoint;
        vorheriger = gebietPolygonPoint;
      }
    }
    if (erster != null && letzter != null && erster != letzter) {
      vorgaengerMap.put(erster, letzter);
      nachfolgerMap.put(letzter, erster);
    }

  }

}
