
package de.ivu.elect.jee.presentation.dynamicform;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;

public abstract class AbstractSelectManyProperty<E> extends AbstractProperty implements SelectManyMenuProperty<E> {

  public static final PropertyType CHECKBOX = PropertyType.SELECT_MANY_CHECKBOX;

  public static final PropertyType CHECKBOX_MENU = PropertyType.SELECT_MANY_CHECKBOX_MENU;

  private final PropertyType propertyType;

  private Predicate<E> valueFilter;

  protected AbstractSelectManyProperty(PropertyType propertyType) {
    this(propertyType, value -> true);
  }

  protected AbstractSelectManyProperty(PropertyType propertyType, Predicate<E> valueFilter) {
    super();

    this.propertyType = propertyType;

    this.valueFilter = valueFilter;
  }

  @Override
  protected boolean mustBeAccessableOnPageLoadByValue() {
    if (super.mustBeAccessableOnPageLoadByValue()) {
      return true;
    }

    return notAllEqual(getDefaultValue(), getValue());
  }

  @Override
  public PropertyType getDefaultType() {
    return propertyType;
  }

  @Override
  protected boolean hasDefaultValue() {
    return notNullOrEmpty(getDefaultValue());
  }

  @Override
  public E[] getDefaultValue() {
    return (E[]) emptyList().toArray();
  }

  @Override
  public boolean hasValue() {
    return notNullOrEmpty(getValue());
  }

  @Override
  public E[] getValue() {
    return (E[]) getValueAsCollection().toArray();
  }

  @Override
  public void setValue(E[] value) {
    List<E> list = new ArrayList<>();

    if (value != null) {
      list.addAll(asList(value));
    }

    setValueAsCollection(list);
  }

  protected abstract Collection<E> getValueAsCollection();

  protected abstract void setValueAsCollection(Collection<E> value);

  @Override
  public Long getColumns() {
    long columnsMinValue = 1L;
    long columns = columnsMinValue;

    Long valuesPerColumn = getValuesPerColumn();

    if (valuesPerColumn != null && valuesPerColumn > 0L) {
      columns = Math.round(Math.ceil(1.0d * getValues().size() / valuesPerColumn));
    }

    return Math.max(columnsMinValue, columns); // ELECT-12589
  }

  @Override
  public String getLayout() {
    return GRID_LAYOUT;
  }

  protected Long getValuesPerColumn() {
    return 1L;
  }

  @Override
  public boolean isShowSeparateItems() {
    return true;
  }

  @Override
  public boolean isShowFilter() {
    return true; // Primfaces Filter über den Elementen einblenden
  }

  @Override
  public String getFilterMatchMode() {
    return PropertyFilterMatchMode.CUSTOM.getFilterMatchModeText();
  }

  @Override
  public String getFilterFunction() {
    return PropertyFilterFunction.TEST_FILTER_VALUE_PATTERN_MATCHES_ITEM_FILTER_LABEL.getFunctionName();
  }

  public void setValueFilter(Predicate<E> valueFilter) {
    this.valueFilter = valueFilter;
  }

  protected Predicate<E> getValueFilter() {
    return valueFilter;
  }
}
