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

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;

import javax.annotation.Nullable;
import javax.faces.validator.Validator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.security.Customer;

public interface CustomParameterTemplate {

  Logger LOG = LoggerFactory.getLogger(CustomParameter.class);

  String name();

  String getKey();

  List<Customer> getCustomers();

  CustomParameterKategorie getKategorie();

  default int getKategoriePosition() {
    return Integer.MAX_VALUE; // ELECT-10924
  }

  CustomParameterWertTyp getWertTyp();

  List<Validator> getWertValidators();

  Supplier<List<String>> getWertStringValues();

  Supplier<Function<String, String>> getWertStringValueToLabelFct();

  @Nullable
  Class< ? extends CustomParameterFilter< ? extends CustomParameter< ? extends CustomParameterTemplate>, ? extends Enum< ? >>> getFilter();

  Class< ? extends Enum< ? >> getWertEnumClass();

  default boolean isCustomerExcluded(Customer customer) {
    return false;
  }

  default boolean hasCustomer(Customer another) {
    return getCustomers().stream().anyMatch(customer -> customer.equals(another) && !isCustomerExcluded(customer));
  }

  default boolean hasCustomerOrParent(Customer another) {
    if (isCustomerExcluded(another)) {
      return false;
    }
    for (Customer customer : getCustomers()) {
      if (customer.equals(another) && !isCustomerExcluded(customer)) {
        return true;
      }

      for (Customer parent : another.getParents()) {
        if (hasCustomerOrParent(parent)) {
          return true;
        }
      }
    }

    return false;
  }

  static List<Enum< ? >> allEnumValues(Class< ? extends Enum< ? >> enumClass) {
    List<Enum< ? >> result = new ArrayList<>();

    if (enumClass != null) {
      try {
        for (Object enumValue : (Enum[]) enumClass.getMethod("values").invoke(enumClass)) {
          result.add((Enum< ? >) enumValue);
        }
      } catch (Exception ex) {
        LOG.warn("Keine Enum Werte gefunden [enumClass = " + enumClass + "]", ex);
      }
    }

    return result;
  }
}
