package gov.cms.grouper.snf.model.table;

import gov.cms.grouper.snf.lego.CsvBuilder;
import gov.cms.grouper.snf.lego.Pair;
import gov.cms.grouper.snf.lego.SnfComparator;
import gov.cms.grouper.snf.lego.SnfUtils;
import gov.cms.grouper.snf.model.CognitiveLevel;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;

public class CognitiveLevelRow extends BasicRow {

  public static final BiFunction<CognitiveLevelRow, Pair<Integer, Integer>, Boolean> selector =
      (row, check) -> {
        return SnfComparator.betweenInclusive(row.getLowVersion(), check.getOne(),
            row.getHighVersion())
            && SnfComparator.betweenNullLow(row.getLowScore(), check.getTwo(), row.getHighScore());
      };

  private CognitiveLevel cognitiveLevel;
  private Integer lowScore;
  private Integer highScore;

  private CognitiveLevelRow() {
    this(null, null, null);
  }

  public CognitiveLevelRow(CognitiveLevel cognitiveLevel, Integer lowScore, Integer highScore) {
    super();
    this.cognitiveLevel = cognitiveLevel;
    this.lowScore = lowScore;
    this.highScore = highScore;
  }

  public CognitiveLevel getCognitiveLevel() {
    return this.cognitiveLevel;
  }

  public Integer getLowScore() {
    return this.lowScore;
  }

  public Integer getHighScore() {
    return this.highScore;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = super.getHashCode(result, prime);
    result = prime * result + ((this.cognitiveLevel == null) ? 0 : this.cognitiveLevel.hashCode());
    result = prime * result + ((this.highScore == null) ? 0 : this.highScore.hashCode());
    result = prime * result + ((this.lowScore == null) ? 0 : this.lowScore.hashCode());
    return result;
  }

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

    if (this.cognitiveLevel != other.cognitiveLevel) {
      return false;
    }
    if (this.highScore == null) {
      if (other.highScore != null) {
        return false;
      }
    } else if (!this.highScore.equals(other.highScore)) {
      return false;
    }
    if (this.lowScore == null) {
      if (other.lowScore != null) {
        return false;
      }
    } else if (!this.lowScore.equals(other.lowScore)) {
      return false;
    }
    return true;
  }

  public static class Builder extends CsvBuilder<CognitiveLevelRow> {

    private static final BiConsumer<CognitiveLevelRow, String> level =
        (val, str) -> val.cognitiveLevel = CognitiveLevel.of(SnfUtils.clean(str));

    private static final BiConsumer<CognitiveLevelRow, String> low =
        (val, str) -> val.lowScore = SnfUtils.parse(str, null);

    private static final BiConsumer<CognitiveLevelRow, String> high =
        (val, str) -> val.highScore = SnfUtils.parse(str, null);

    private static final Builder singleton = new Builder();

    public static Map<Integer, BiConsumer<CognitiveLevelRow, String>> initCsvMapping() {
      Map<Integer, BiConsumer<CognitiveLevelRow, String>> result = new HashMap<>();
      result.put(0, Builder.level);
      result.put(1, BasicRow.getLowVersionParser());
      result.put(2, BasicRow.getHighVersionParser());
      result.put(3, Builder.low);
      result.put(4, Builder.high);

      return Collections.unmodifiableMap(result);
    }

    private Builder() {
      super(CognitiveLevelRow::new, Builder.initCsvMapping());
    }

    public static Builder of() {
      return Builder.singleton;
    }

  }

}
