package in.twizmwaz.cardinal.tabList;
import com.google.common.collect.Lists;
import in.twizmwaz.cardinal.module.modules.permissions.PermissionModule;
import in.twizmwaz.cardinal.module.modules.team.TeamModule;
import in.twizmwaz.cardinal.rank.Rank;
import in.twizmwaz.cardinal.tabList.entries.EmptyTabEntry;
import in.twizmwaz.cardinal.tabList.entries.SkinTabEntry;
import in.twizmwaz.cardinal.tabList.entries.TabEntry;
import in.twizmwaz.cardinal.util.PacketUtils;
import in.twizmwaz.cardinal.util.Teams;
import net.minecraft.server.PacketPlayOutPlayerInfo;
import org.bukkit.entity.Player;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public class TabView {
private final Player viewer;
private TabSlot[] slots = new TabSlot[80];
private Set<TabEntry> emptyPlayers = new HashSet<>();
private static Set<TabEntry> hideEntries = new HashSet<>();
public TabView(Player viewer) {
this.viewer = viewer;
setupPlayer();
}
public Player getViewer() {
return viewer;
}
public Set<TabEntry> getEmptyPlayers() {
return emptyPlayers;
}
public void destroy(TabEntry entry, int newSlot, boolean update) {
for (TabSlot slot : slots) slot.removeEntry(entry, newSlot);
if (update) updateSlots();
}
private void updateSlots() {
for (TabSlot slot : slots) slot.update();
Set<String> names = new HashSet<>();
for (TabEntry entry : hideEntries) names.add(entry.getName());
PacketUtils.sendPacket(viewer, TabList.getTeamPacket(names, 80, 3));
hideEntries.clear();
}
public void hideEntry(TabEntry entry) {
if (entry instanceof EmptyTabEntry) emptyPlayers.remove(entry);
hideEntries.add(entry);
}
public void setSlot(TabEntry entry, int slot) {
if (entry instanceof EmptyTabEntry) emptyPlayers.add(entry);
hideEntries.remove(entry);
entry.setSlot(viewer, slot);
}
private void setupPlayer() {
PacketPlayOutPlayerInfo listPacket = new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER);
List<String> names = Lists.newArrayList();
for (TabEntry entry : TabList.getTabEntries()) {
listPacket.add(entry.getPlayerInfo(viewer, listPacket));
names.add(entry.getName());
}
for (int i = 0; i < 81; i++) {
if (i == 80) {
PacketUtils.sendPacket(viewer, TabList.getTeamPacket((String) null, i, 0));
continue;
}
TabEntry fakePlayer = TabList.getFakePlayer(this);
slots[i] = new TabSlot(this, fakePlayer, i);
names.remove(fakePlayer.getName());
}
PacketUtils.sendPacket(viewer, TabList.getTeamPacket(names, 80, 3));
PacketUtils.sendPacket(viewer, listPacket);
for (TabEntry entry : TabList.getTabEntries()) {
if (entry instanceof SkinTabEntry) {
((SkinTabEntry) entry).createSkinParts(viewer);
}
}
}
public void update() {
List<TeamModule> prioritized = getPrioritizedTeams(Teams.getTeamByPlayer(viewer).orNull());
int obsSize = obsRows(prioritized);
int biggestTeamCol = TabList.columnsPerTeam > 1 ? 18 - obsSize : -1;
renderObs(20 - obsSize);
int row = 0, col = 0, currMax = 0;
for (TeamModule team : prioritized) {
renderTeam(team, row, col, biggestTeamCol);
currMax = Math.max(currMax, getBiggestTeamCol(Collections.singleton(team)));
if ((col += TabList.columnsPerTeam) > 3) {
col = 0;
row += currMax;
currMax = 0;
}
}
updateSlots();
}
private static List<TeamModule> getPrioritizedTeams(TeamModule prioritized) {
List<TeamModule> teams = Teams.getTeams();
Iterator<TeamModule> teamIterator = teams.iterator();
while (teamIterator.hasNext()) {
TeamModule next = teamIterator.next();
if (next.isObserver() || (prioritized != null && next.equals(prioritized))) teamIterator.remove();
}
if (prioritized != null && !prioritized.isObserver()) teams.add(0, prioritized);
return teams;
}
private void renderTeam(TeamModule team, int startRow, int col, int maxRows) {
boolean hasPlayer = team.contains(viewer);
updateTabListSlot(TabList.getTeam(team), startRow, col);
if (hasPlayer) updateTabListSlot(TabList.getPlayer(viewer), startRow + 1, col);
int row = hasPlayer ? startRow + 2 : startRow + 1;
int colOffset = 0;
for (Player render : getSortedPlayerList(team)) {
if (render.equals(viewer)) continue;
if (colOffset > TabList.columnsPerTeam) {
updateTabListSlot(TabList.getPlayer(render), 80, 0);
} else {
if (render.equals(viewer)) continue;
updateTabListSlot(TabList.getPlayer(render), row, col + colOffset);
if (row++ >= maxRows && maxRows != -1) {
row = startRow + 1;
colOffset++;
}
}
}
}
private void renderObs(int row) {
TeamModule team = Teams.getTeamById("observers").get();
boolean hasPlayer = team.contains(viewer);
int col = hasPlayer ? 1 : 0;
if (hasPlayer) updateTabListSlot(TabList.getPlayer(viewer), row > 19 ? 80 : row, 0);
for (Player render : getSortedPlayerList(team)) {
if (render.equals(viewer)) continue;
if (row > 19) {
updateTabListSlot(TabList.getPlayer(render), 80, 0);
} else {
updateTabListSlot(TabList.getPlayer(render), row, col);
if (col++ >= 3) {
col = 0;
row++;
}
}
}
}
private static int getBiggestTeamCol(Collection<TeamModule> teams) {
int total = 0, biggestTeam = -1, col = 0;
for (TeamModule team : teams) {
if (!team.isObserver()) {
biggestTeam = Math.max(biggestTeam, team.size());
if (col++ >= 3) {
col = 0;
total += 2 + ((biggestTeam + (TabList.columnsPerTeam - 1)) / TabList.columnsPerTeam);
biggestTeam = -1;
}
}
}
if (biggestTeam != -1) total += 2 + (biggestTeam + (TabList.columnsPerTeam - 1)) / TabList.columnsPerTeam;
return total;
}
private static int obsRows(Collection<TeamModule> teamOrder) {
int maxObsRows = 20 - getBiggestTeamCol(teamOrder);
int obsRows = Math.min((Teams.getTeamById("observers").get().size() + 3 ) / 4, maxObsRows);
return obsRows <= 0 ? -1 : obsRows;
}
private int rowAndCol(int row, int col) {
return row + col * 20;
}
private void updateTabListSlot(TabEntry entry, int row, int col) {
int i = rowAndCol(row, col);
destroy(entry, i, false);
if (i < 80) slots[i].setNewEntry(entry);
else hideEntry(entry);
}
public static List<Player> getSortedPlayerList(TeamModule team) {
if (TabList.updateTeam(team)) {
Collections.sort(team, new Comparator<Player>() {
@Override
public int compare(Player player1, Player player2) {
UUID uuid1 = player1.getUniqueId();
UUID uuid2 = player2.getUniqueId();
boolean op1 = player1.isOp(), op2 = player2.isOp();
if (op1 ^ op2) return op1 ? -1 : 1;
boolean dev1 = PermissionModule.isDeveloper(uuid1), dev2 = PermissionModule.isDeveloper(uuid2);
if (dev1 ^ dev2) return dev1 ? -1 : 0;
for (Rank rank : Rank.getRanks()) {
if (!rank.isStaffRank()) continue;
boolean rank1 = rank.contains(uuid1), rank2 = rank.contains(uuid2);
if (rank1 ^ rank2) return rank1 ? -1 : 1;
}
boolean map1 = Rank.isMapAuthor(uuid1), map2 = Rank.isMapAuthor(uuid1);
if (map1 ^ map2) return map1 ? -1 : 1;
for (Rank rank : Rank.getRanks()) {
if (rank.isStaffRank()) continue;
boolean rank1 = rank.contains(uuid1), rank2 = rank.contains(uuid2);
if (rank1 ^ rank2) return rank1 ? -1 : 1;
}
return player1.getName().compareTo(player2.getName());
}
});
}
return team;
}
}