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

import java.util.function.Function;

import javax.annotation.Nullable;

public interface EntityMitBarrierefreiheit {

  EntityMitBarrierefreiheit KEINE = null;

  default boolean isEntityBarrierefreiBlind() {
    return isGesetztOderAbgeleitetBarrierefrei(EntityMitBarrierefreiheit::getBarrierefreiBlind);
  }

  default BarrierefreiWert getBarrierefreiBlindAbgeleitet() {
    return getBarrierefreiWertAbgeleitet(EntityMitBarrierefreiheit::getBarrierefreiBlind);
  }

  BarrierefreiWert getBarrierefreiBlind();

  default boolean isEntityBarrierefreiGehbehindert() {
    return isGesetztOderAbgeleitetBarrierefrei(EntityMitBarrierefreiheit::getBarrierefreiGehbehindert);
  }

  default BarrierefreiWert getBarrierefreiGehbehindertAbgeleitet() {
    return getBarrierefreiWertAbgeleitet(EntityMitBarrierefreiheit::getBarrierefreiGehbehindert);
  }

  BarrierefreiWert getBarrierefreiGehbehindert();

  default boolean isEntityBarrierefreiKognitiv() {
    return isGesetztOderAbgeleitetBarrierefrei(EntityMitBarrierefreiheit::getBarrierefreiKognitiv);
  }

  default BarrierefreiWert getBarrierefreiKognitivAbgeleitet() {
    return getBarrierefreiWertAbgeleitet(EntityMitBarrierefreiheit::getBarrierefreiKognitiv);
  }

  BarrierefreiWert getBarrierefreiKognitiv();

  default boolean isEntityBarrierefreiSehbehindert() {
    return isGesetztOderAbgeleitetBarrierefrei(EntityMitBarrierefreiheit::getBarrierefreiSehbehindert);
  }

  default BarrierefreiWert getBarrierefreiSehbehindertAbgeleitet() {
    return getBarrierefreiWertAbgeleitet(EntityMitBarrierefreiheit::getBarrierefreiSehbehindert);
  }

  BarrierefreiWert getBarrierefreiSehbehindert();

  default boolean isEntityBarrierefreiRollstuhl() {
    return isGesetztOderAbgeleitetBarrierefrei(EntityMitBarrierefreiheit::getBarrierefreiRollstuhl);
  }

  default BarrierefreiWert getBarrierefreiRollstuhlAbgeleitet() {
    return getBarrierefreiWertAbgeleitet(EntityMitBarrierefreiheit::getBarrierefreiRollstuhl);
  }

  BarrierefreiWert getBarrierefreiRollstuhl();

  @Deprecated // Nicht verwenden, auf einzelne Aspekte der Barrierefreiheit gehen, vgl. ELECTMUC-1113
  default Barrierefrei getBarrierefreiLegacy() {
    if (isVollstaendigBarrierefrei()) {
      return Barrierefrei.BARIEREFREI;
    }

    return Barrierefrei.NICHT_BARRIEREFREI; // Nicht ganz korrekt, aber ohne praktische Relevanz
  }

  default boolean isVollstaendigBarrierefrei() {
    return isEntityBarrierefreiBlind() && isEntityBarrierefreiGehbehindert() && isEntityBarrierefreiKognitiv() && isEntityBarrierefreiSehbehindert() && isEntityBarrierefreiRollstuhl();
  }

  @Nullable
  EntityMitBarrierefreiheit getUebergeordneteEntitaetMitBarrierefreiheit();

  default boolean isGesetztOderAbgeleitetBarrierefrei(Function<EntityMitBarrierefreiheit, BarrierefreiWert> barrierefreiFct) {
    BarrierefreiWert wert = barrierefreiFct.apply(this);

    if (wert.isGesetztBarrierefrei()) {
      return true;
    }

    if (wert.isUebergeordneteEntititaetBetrachten()) {
      EntityMitBarrierefreiheit uebergeordnet = getUebergeordneteEntitaetMitBarrierefreiheit();

      if (uebergeordnet == null) {
        return false;
      }

      return uebergeordnet.isGesetztOderAbgeleitetBarrierefrei(barrierefreiFct);
    }

    return false;
  }

  default boolean isGesetztOderAbgeleitetNichtBarrierefrei(Function<EntityMitBarrierefreiheit, BarrierefreiWert> barrierefreiFct) {
    BarrierefreiWert wert = barrierefreiFct.apply(this);

    if (wert.isGesetztNichtBarrierefrei()) {
      return true;
    }

    if (wert.isUebergeordneteEntititaetBetrachten()) {
      EntityMitBarrierefreiheit uebergeordnet = getUebergeordneteEntitaetMitBarrierefreiheit();

      if (uebergeordnet == null) {
        return false;
      }

      return uebergeordnet.isGesetztOderAbgeleitetNichtBarrierefrei(barrierefreiFct);
    }

    return false;
  }

  default BarrierefreiWert getBarrierefreiWertAbgeleitet(Function<EntityMitBarrierefreiheit, BarrierefreiWert> barrierefreiFct) {
    BarrierefreiWert wert = barrierefreiFct.apply(this);

    if (wert.isUebergeordneteEntititaetBetrachten()) {
      EntityMitBarrierefreiheit uebergeordnet = getUebergeordneteEntitaetMitBarrierefreiheit();

      if (uebergeordnet == null) {
        return wert;
      }

      return uebergeordnet.getBarrierefreiWertAbgeleitet(barrierefreiFct);
    }

    return wert;
  }
}
