
package de.ivu.elect.jee.exchange;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import de.ivu.elect.jee.entity.tk.EntityFieldValue;
import de.ivu.elect.jee.faces.Messages;

public class Violations implements Serializable {

  private static final long serialVersionUID = 1L;

  private final List<AbstractViolation> violations = new ArrayList<>();

  public Violations() {
    super();
  }

  public List<AbstractViolation> getViolations() {

    // Error nach vorne, Reihenfolge wahren
    Map<ViolationLevel, List<AbstractViolation>> mapped = violations.stream()
        .collect(Collectors.groupingBy(AbstractViolation::getViolationLevel, () -> new EnumMap<>(ViolationLevel.class), Collectors.toList()));

    List<AbstractViolation> result = new ArrayList<>();
    mapped.entrySet().stream().sorted(/*Fehler nach vorne*/(u,v)->v.getKey().compareTo(u.getKey())).forEach(e->result.addAll(e.getValue()));
    return result;
  }

  public List<AbstractViolation> getViolationsMaxCount(int shownMaxViolations) {
    if (shownMaxViolations > size()) {
      return getViolations();
    }

    return getViolations().subList(0, shownMaxViolations);
  }

  public void addError(String messageKey, Object... params) {
    violations.add(new Violation(ViolationLevel.ERROR, messageKey, params));
  }

  public void addWarning(String messageKey, Object... params) {
    violations.add(new Violation(ViolationLevel.WARNING, messageKey, params));
  }

  public void addInfo(String messageKey, Object... params) {
    violations.add(new Violation(ViolationLevel.INFO, messageKey, params));
  }

  public void add(AbstractViolation violation) {
    this.violations.add(violation);
  }

  public void add(Violations other) {
    this.violations.addAll(other.violations);
  }

  public boolean isEmpty() {
    return getViolations().isEmpty();
  }

  public boolean containsViolationsWithLevelError() {
    return containsViolationsWithLevel(ViolationLevel.ERROR);
  }

  public List<AbstractViolation> getErrorViolations() {
    return getViolations().stream().filter(violation -> ViolationLevel.ERROR.equals(violation.getViolationLevel())).collect(Collectors.toList());
  }

  public boolean containsViolationsWithLevel(ViolationLevel violationLevel) {
    return getViolations().stream().anyMatch(violation -> violationLevel.equals(violation.getViolationLevel()));
  }

  public int size() {
    return getViolations().size();
  }

  @Override
  public String toString() {
    return "Violations: " + getViolations();
  }

  public void appendWarnMessages(Messages messages) {
    appendWarnMessages(messages, Integer.MAX_VALUE);
  }

  public void appendWarnMessages(Messages messages, int maxmessages) {
    int count = 0;

    for (AbstractViolation violation : violations) {
      count++;

      if (count > maxmessages) {
        return;
      }

      violation.appendWarnMessage(messages);
    }
  }

  public void addErrorUniqueConstraintViolated(String entityMessageKey, List<EntityFieldValue> entityFieldValues) {
    violations.add(new UniqueConstraintViolation(ViolationLevel.ERROR, entityMessageKey, entityFieldValues));
  }

  public void appendMessages(Messages messages) {
    appendMessages(messages, Integer.MAX_VALUE);
  }

  public void appendMessages(Messages messages, int maxmessages) {
    int count = 0;

    for (AbstractViolation violation : violations) {
      count++;

      if (count > maxmessages) {
        return;
      }

      violation.appendMessage(messages);
    }
  }
}
