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

import static java.util.Objects.nonNull;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.convert.Converter;
import javax.faces.validator.Validator;

// FIXME ELECT-116
class FormBuilderProperty {

  private final int columnIndexZeroBased = 0;

  private final int colSpan = 1;

  private final int rowSpan = 1;

  private final Property property;

  private final List<FacesMessage> facesMessages;

  private final List<Validator> facesValidators;

  private final Map<String, Object> attributes;

  private final Set<Property> propertiesConnected;

  private List< ? > selectableValues;

  public FormBuilderProperty(Property property) {
    super();

    this.property = property;

    this.facesMessages = new ArrayList<>();
    this.facesValidators = new ArrayList<>();

    this.attributes = new HashMap<>();
    this.selectableValues = new ArrayList<>();

    this.propertiesConnected = new HashSet<>();
  }

  public int getColumn() {
    return columnIndexZeroBased;
  }

  public int getColSpan() {
    return colSpan;
  }

  public int getRowSpan() {
    return rowSpan;
  }

  public Property getProperty() {
    return property;
  }

  public void addFacesMessage(Severity severity, String summary, String detail) {
    facesMessages.add(new FacesMessage(severity, summary, detail));
  }

  public List<FacesMessage> getFacesMessages() {
    return facesMessages;
  }

  public List<Validator> getFacesValidators() {
    return facesValidators;
  }

  public void addFacesValidator(Validator facesValidator) {
    facesValidators.add(facesValidator);
  }

  public void setFacesConverter(Converter facesConverter) {
    property.setConverter(facesConverter);
  }

  public Map<String, Object> getAttributes() {
    return attributes;
  }

  public void addAttribute(String key, Object value) {
    attributes.put(key, value);
  }

  public void addPropertyConnected(FormBuilderProperty formBuilderProperty) {
    if (nonNull(formBuilderProperty) && nonNull(formBuilderProperty.getProperty())) {
      propertiesConnected.add(formBuilderProperty.getProperty());
    }
  }

  public String getLabel() {
    return property.getLabel();
  }

  public void setLabel(String label) {
    property.setLabel(label);
  }

  public String getTooltip() {
    return property.getTooltip();
  }

  public void setTooltip(String tooltip) {
    property.setTooltip(tooltip);
  }

  public void getStyleClass() {
    property.getStyleClass();
  }

  public void setStyleClass(String styleClass) {
    property.setStyleClass(styleClass);
  }

  public boolean isReadonly() {
    return property.isReadonly();
  }

  public void setReadonly(boolean readonly) {
    property.setReadonly(readonly);
  }

  public boolean isRequired() {
    return property.isRequired();
  }

  public void setRequired(boolean required) {
    property.setRequired(required);
  }

  public boolean isVisibleOnPageLoad() {
    return property.isVisibleOnPageLoad();
  }

  public void setVisibleOnPageLoad(boolean visibleOnPageLoad) {
    property.setVisibleOnPageLoad(visibleOnPageLoad);

    if (property.isVisible() && property.isAccessableOnPageLoad()) {
      propertiesConnected.forEach(propertyConnected -> propertyConnected.setVisibleOnPageLoad(true));
    }
  }

  public boolean isVisible() {
    return property.isVisible();
  }

  public void setVisible(boolean visible) {
    property.setVisible(visible);
  }

  public PropertyType getType() {
    return property.getType();
  }

  public void setType(PropertyType type) {
    property.setType(type);
  }

  public List< ? > getValues() {
    return selectableValues;
  }

  public void setValues(List< ? > selectableValues) {
    this.selectableValues = selectableValues;
  }


  public String key;

  public String getKey() {
    return key;
  }

  public void setKey(String key) {
    this.key = key;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (property == null ? 0 : property.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    FormBuilderProperty other = (FormBuilderProperty) obj;
    if (property == null) {
      if (other.property != null) {
        return false;
      }
    } else if (!property.equals(other.property)) {
      return false;
    }
    return true;
  }

  public boolean containsMessageWithSeverity(Severity severity) {
    return getFacesMessages().stream().anyMatch(facesMessage -> facesMessage.getSeverity().equals(severity));
  }
}
