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

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebietTK;


import static java.util.Objects.nonNull;

class GruppePropertyAufGebietResolver implements Serializable {

  private static final long serialVersionUID = 1L;

  private final Gruppe gruppe;

  private final Supplier<Map<GruppeImGebietTK, GruppeImGebiet>> gruppenImGebietPerGruppeGebietSchluesselSupplier;

  public GruppePropertyAufGebietResolver(Gruppe gruppe, Supplier<Map<GruppeImGebietTK, GruppeImGebiet>> gruppenImGebietPerGruppeGebietSchluesselSupplier) {
    super();
    this.gruppe = gruppe;
    this.gruppenImGebietPerGruppeGebietSchluesselSupplier = gruppenImGebietPerGruppeGebietSchluesselSupplier;
  }

  public String getNameAufGebiet(Gebiet gebiet) {
    GruppeImGebiet gruppeImGebiet = getGruppeImGebietNameAbweichend(gebiet);

    if (gruppeImGebiet == null) {
      return gruppe.getName();
    }

    return gruppeImGebiet.getName();
  }

  /*
   * Hinweis: Diese Methode lässt eventuelle Kurznamen aus CustomData unberücksichtigt.
   */
  public GruppeImGebiet getGruppeImGebietInDerDerNameOderKurznameWechselt(Gebiet gebiet) {
    if (gebiet == null) {
      return null;
    }

    GruppeImGebiet gruppeImGebiet = getGruppeImGebietKurznameAbweichend(gebiet);

    if (nonNull(gruppeImGebiet)) {
      return gruppeImGebiet;
    }

    gruppeImGebiet = getGruppeImGebietNameAbweichend(gebiet);

    if (nonNull(gruppeImGebiet)) {
      return gruppeImGebiet;
    }

    return getGruppeImGebietInDerDerNameOderKurznameWechselt(gebiet.getUebergeordnetesGebiet());
  }

  private GruppeImGebiet getGruppeImGebietNameAbweichend(Gebiet gebiet) {
    if (gebiet == null) {
      return null;
    }

    GruppeImGebiet gruppeImGebiet = getGruppeImGebietByGebiet(gebiet);

    if (gruppeImGebiet == null || !gruppeImGebiet.hasName()) {
      return getGruppeImGebietNameAbweichend(gebiet.getUebergeordnetesGebiet());
    }

    return gruppeImGebiet;
  }

  public String getKurznameAufGebiet(Gebiet gebiet) {
    GruppeImGebiet gruppeImGebiet = getGruppeImGebietKurznameAbweichend(gebiet);

    if (gruppeImGebiet == null) {
      return gruppe.getKurzname();
    }

    return gruppeImGebiet.getKurzname();
  }

  public String getZusatzbezeichnungAufGebiet(Gebiet gebiet) {
    GruppeImGebiet gruppeImGebiet = getGruppeImGebietZusatzbezeichnungAbweichend(gebiet);

    if (gruppeImGebiet == null) {
      return gruppe.getZusatzbezeichnung();
    }

    return gruppeImGebiet.getZusatzbezeichnung();
  }

  private GruppeImGebiet getGruppeImGebietKurznameAbweichend(Gebiet gebiet) {
    if (gebiet == null) {
      return null;
    }

    GruppeImGebiet gruppeImGebiet = getGruppeImGebietByGebiet(gebiet);

    if (gruppeImGebiet == null || !gruppeImGebiet.hasKurzname()) {
      return getGruppeImGebietKurznameAbweichend(gebiet.getUebergeordnetesGebiet());
    }

    return gruppeImGebiet;
  }

  private GruppeImGebiet getGruppeImGebietZusatzbezeichnungAbweichend(Gebiet gebiet) {
    if (gebiet == null) {
      return null;
    }

    GruppeImGebiet gruppeImGebiet = getGruppeImGebietByGebiet(gebiet);

    if (gruppeImGebiet == null || !gruppeImGebiet.hasZusatzbezeichnung()) {
      return getGruppeImGebietZusatzbezeichnungAbweichend(gebiet.getUebergeordnetesGebiet());
    }

    return gruppeImGebiet;
  }

  Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietPerGruppeGebietSchluessel = null;

  private Map<GruppeImGebietTK, GruppeImGebiet> getGruppenImGebietPerGruppeGebietSchluessel() {
    if (gruppenImGebietPerGruppeGebietSchluessel == null) {
      gruppenImGebietPerGruppeGebietSchluessel = gruppenImGebietPerGruppeGebietSchluesselSupplier.get();
    }
    return gruppenImGebietPerGruppeGebietSchluessel;
  }

  private final Map<Gebiet, GruppeImGebiet> gruppeImGebietCache = new HashMap<>();

  protected GruppeImGebiet getGruppeImGebietByGebiet(Gebiet gebiet) {
    return gruppeImGebietCache.computeIfAbsent(gebiet, x -> getGruppenImGebietPerGruppeGebietSchluessel().get(new GruppeImGebietTK(gebiet.getGebietTK(),
        gruppe.getGruppeTK())));
  }
}
