package models;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.annotation.Where;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import controllers.PlayersController;
import play.db.ebean.Model;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.avaje.ebean.Ebean.find;
import static com.avaje.ebean.Expr.and;
import static com.avaje.ebean.Expr.eq;
import static com.avaje.ebean.Expr.gt;
@Entity
public class Player extends BaseModel<Player> implements Comparable<Player> {
public static Player guest = new Player(0L, "guest");
public static Model.Finder<Long, Player> finder = new Model.Finder(Long.class, Player.class);
public String name;
public Long shmupUserId;
public boolean hideMedals;
@OneToMany(mappedBy = "player", fetch = FetchType.EAGER)
@Where(clause = "rank > 0")
public List<Score> scores = new ArrayList<Score>();
@OneToMany(mappedBy = "player")
public List<Score> allScores = new ArrayList<Score>();
public String twitter;
private boolean vip;
private PlayersController.Counts counts;
public Player(Long id, String name) {
this.id = id;
this.name = name;
}
public Player(String name) {
this.name = name;
}
public static Player findOrCreatePlayer(String name) {
Player player = Player.finder.where()
.eq("name", name)
.findUnique();
if (player == null) {
player = new Player(name);
player.vip = true;
player.save();
}
return player;
}
public static Player findByShmupUserId(Long shmupUserId) {
return Player.finder.where()
.eq("shmupUserId", shmupUserId)
.findUnique();
}
public static List<Player> findAll() {
return finder.orderBy("name").findList();
}
@Override
public String toString() {
return name;
}
public boolean isAuthenticated() {
return !this.equals(guest);
}
public Collection<Score> bestReplayableScores() {
return Score.finder.fetch("game").fetch("platform").fetch("mode").fetch("difficulty").where().not(eq("replay", "")).eq("player", this).findList();
}
public boolean hasReplays() {
return !bestReplayableScores().isEmpty();
}
public boolean isVip() {
return vip;
}
public boolean canImportScores() {
return id == 1 // anzymus
|| id == 6 // yace
|| id == 42 // mickey
|| id == 137 // trizeal
|| id == 705 // Vzurkr
|| id == 191 // lerebours
|| id == 7 // SL
|| id == 231 // MKNIGHT
|| id == 269 // Yami
|| id == 30 // shadow gallery
|| id == 116 // Doudinou
|| id == 150 // Undef
|| id == 779 // Kat
|| id == 159 // Cormano
|| id == 226 // Radigo
|| id == 57 // Akaimakai
|| id == 223 // Guts
;
}
public boolean isAdministrator() {
return id == 1;
}
public Score getLastScore() {
List<Score> scores = new ArrayList<Score>(this.scores);
Collections.sort(scores, new Comparator<Score>() {
@Override
public int compare(Score o1, Score o2) {
return o2.getCreatedAt().compareTo(o1.getCreatedAt());
}
});
return scores.get(0);
}
public int computeOneCredit() {
return oneccs().size();
}
public Collection<Score> oneccs() {
List<Score> oneCreditScores = find(Score.class).fetch("platform").fetch("game").fetch("mode").fetch("difficulty").where().eq("player", this).eq("onecc", true).findList();
List<Score> oneccs = new ArrayList<Score>();
Set<String> uniqueOneCreditScores = new HashSet<String>();
for (Score oneCreditScore : oneCreditScores) {
String gameTitle = oneCreditScore.getGameTitle();
String mode = oneCreditScore.modeName();
String difficulty = oneCreditScore.difficultyName();
String key = gameTitle + mode + difficulty;
boolean add = uniqueOneCreditScores.add(key);
if (add) {
oneccs.add(oneCreditScore);
}
}
return oneccs;
}
public PlayersController.Counts getCounts() {
return counts;
}
public void setCounts(PlayersController.Counts counts) {
this.counts = counts;
}
public PlayersController.Counts computeCounts() {
Integer firstRankCount = find(Score.class).where(and(eq("player", this), eq("rank", 1))).findRowCount();
int secondRankCount = find(Score.class).where(and(eq("player", this), eq("rank", 2))).findRowCount();
int thirdRankCount = find(Score.class).where(and(eq("player", this), eq("rank", 3))).findRowCount();
int oneCreditCount = computeOneCredit();
return counts = new PlayersController.Counts(firstRankCount, secondRankCount, thirdRankCount, oneCreditCount);
}
@Override
public int compareTo(Player p) {
return this.name.compareToIgnoreCase(p.name);
}
public Versus getComparisonWith(Player p) {
Versus versus = new Versus(this, p);
List<Score> scores = this.scores;
for (Score score : scores) {
Score comparisonScore = p.getEquivalentScore(score);
if (comparisonScore != null) {
Versus.Comparison comparison = new Versus.Comparison(score.game, score.difficulty, score.mode, score, comparisonScore);
versus.add(comparison);
}
}
return versus;
}
private Score getEquivalentScore(Score reference) {
for (Score score : scores) {
if (score.game.equals(reference.game)) {
if (score.hasMode(reference.mode) && score.hasDifficulty(reference.difficulty)) {
return score;
}
}
}
return null;
}
public Versus getBestVersus() {
List<Player> all = Player.finder.where().join("scores").findList();
all.remove(this);
Versus bestVersus = null;
for (Player opponent : all) {
Versus versus = getComparisonWith(opponent);
if (bestVersus == null || bestVersus.loseCount() < versus.loseCount()) {
bestVersus = versus;
}
}
return bestVersus;
}
public boolean isUnbeatable() {
for (Score score : scores) {
if (score.rank > 1) {
return false;
}
}
return !scores.isEmpty();
}
public List<Score> fetchScores() {
return Score.finder.
where(and(gt("rank", 0), eq("player", this))).
fetch("platform").
fetch("stage").
fetch("game").
fetch("mode").
fetch("player").
fetch("difficulty").
findList();
}
public Score getBestScoreFor(Game game, Mode mode, Difficulty difficulty) {
return Ebean.createQuery(Score.class).
setMaxRows(1).
orderBy(game.hasTimerScores() ? "value" : "value desc").
where().eq("player", this).eq("game", game).eq("mode", mode).eq("difficulty", difficulty).
findUnique();
}
public JsonNode json() {
ObjectNode node = new ObjectNode(JsonNodeFactory.instance);
node.set("id", new LongNode(id));
node.set("name", new TextNode(name));
return node;
}
}