
package de.ivu.elect.business.kandidatur.boundary;

import java.io.Serializable;
import java.util.Comparator;
import java.util.function.Function;
import java.util.function.Predicate;

import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;

/**
 * ELECTVAPP-1341 - no performance optimization
 */
public class Eml520CandidateComparator implements Comparator<Listenkandidatur>, Serializable {

  private static final long serialVersionUID = 1L;

  private final Predicate<Listenkandidatur> isUberVorzugtGewaehlt;
  private final Function<Listenkandidatur, Long> numberOfVotesFct;
  private final Function<Listenkandidatur, String> shortCodeFct;
  private final Function<Listenkandidatur, Long> listPositionFct;
  private final Function<Listenkandidatur, Long> kieskringNumberFct;

  public Eml520CandidateComparator(Predicate<Listenkandidatur> isUberVorzugtGewaehlt, Function<Listenkandidatur, Long> numberOfVotesFct, Function<Listenkandidatur, String> shortCodeFct,
      Function<Listenkandidatur, Long> listPositionFct, Function<Listenkandidatur, Long> kieskringNumberFct) {
    this.isUberVorzugtGewaehlt = isUberVorzugtGewaehlt;
    this.numberOfVotesFct = numberOfVotesFct;
    this.shortCodeFct = shortCodeFct;
    this.listPositionFct = listPositionFct;
    this.kieskringNumberFct = kieskringNumberFct;
  }

  @Override
  public int compare(Listenkandidatur o1, Listenkandidatur o2) {

    boolean vorzug1 = isUberVorzugtGewaehlt.test(o1);
    boolean vorzug2 = isUberVorzugtGewaehlt.test(o2);

    if (vorzug1 && !vorzug2) {
      return -1;
    }
    if (!vorzug1 && vorzug2) {
      return 1;
    }

    if (vorzug1) {
      return compareVorzug(o1, o2);
    }

    return compareNichtVorzug(o1, o2);
  }

  private int compareNichtVorzug(Listenkandidatur o1, Listenkandidatur o2) {
    int result = compareListposition(o1, o2);
    if (result == 0) {
      result = compareKieskring(o1, o2);
    }
    return result;
  }

  private int compareKieskring(Listenkandidatur o1, Listenkandidatur o2) {
    return Long.compare(kieskringNumberFct.apply(o1), kieskringNumberFct.apply(o2));
  }

  private int compareListposition(Listenkandidatur o1, Listenkandidatur o2) {
    return Long.compare(listPositionFct.apply(o1), listPositionFct.apply(o2));
  }

  private int compareVorzug(Listenkandidatur o1, Listenkandidatur o2) {
    int result = compareVotes(o1, o2);
    if (result == 0) {
      result = compareShortCode(o1, o2);
    }
    return result;
  }

  private int compareShortCode(Listenkandidatur o1, Listenkandidatur o2) {
    return shortCodeFct.apply(o1).compareTo(shortCodeFct.apply(o2));
  }

  private int compareVotes(Listenkandidatur o1, Listenkandidatur o2) {
    return Long.compare(numberOfVotesFct.apply(o2), numberOfVotesFct.apply(o1)) /*ELECT-11930*/;
  }
}
