package me.corriekay.pokegoutil.data.enums;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.NoSuchElementException;
import javax.swing.table.TableCellRenderer;
import com.pokegoapi.api.pokemon.Evolutions;
import com.pokegoapi.api.pokemon.Pokemon;
import com.pokegoapi.exceptions.NoSuchItemException;
import com.pokegoapi.google.common.geometry.S2CellId;
import com.pokegoapi.main.PokemonMeta;
import POGOProtos.Enums.PokemonIdOuterClass;
import POGOProtos.Enums.PokemonMoveOuterClass.PokemonMove;
import POGOProtos.Enums.PokemonTypeOuterClass.PokemonType;
import POGOProtos.Settings.Master.MoveSettingsOuterClass.MoveSettings;
import me.corriekay.pokegoutil.utils.AutoIncrementer;
import me.corriekay.pokegoutil.utils.ConfigKey;
import me.corriekay.pokegoutil.utils.ConfigNew;
import me.corriekay.pokegoutil.utils.StringLiterals;
import me.corriekay.pokegoutil.utils.Utilities;
import me.corriekay.pokegoutil.utils.helpers.CollectionHelper;
import me.corriekay.pokegoutil.utils.helpers.DateHelper;
import me.corriekay.pokegoutil.utils.helpers.LocationHelper;
import me.corriekay.pokegoutil.utils.pokemon.PokemonCalculationUtils;
import me.corriekay.pokegoutil.utils.pokemon.PokemonPerformanceCache;
import me.corriekay.pokegoutil.utils.pokemon.PokemonUtils;
import me.corriekay.pokegoutil.utils.windows.renderer.CellRendererHelper;
/**
* A class that holds data relevant for each column.
* Cleka 19.2.2017: renamed "name" to "heading",
* otherwise .name returns something different than .name()!
*/
public enum PokeColumn {
AUTO_INCREMENT("Row", ColumnType.AUTO_INCREMENT) {
@Override
public Object get(final Pokemon p) {
return null;
}
},
POKEDEX_ID("#", ColumnType.INT) {
@Override
public Object get(final Pokemon p) {
return p.getPokemonId().getNumber();
}
},
NICKNAME("Nickname", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return p.getNickname();
}
},
CP("CP", ColumnType.INT) {
@Override
public Object get(final Pokemon p) {
return p.getCp();
}
},
SPECIES("Species", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return PokemonUtils.getLocalPokeName(p);
}
},
IV_RATING("IV %", ColumnType.PERCENTAGE) {
@Override
public Object get(final Pokemon p) {
return PokemonCalculationUtils.ivRating(p);
}
},
LEVEL("Lvl", ColumnType.DOUBLE) {
@Override
public Object get(final Pokemon p) {
return (double) p.getLevel();
}
},
IV_ATTACK("Atk", ColumnType.INT, CellRendererHelper.IV) {
@Override
public Object get(final Pokemon p) {
return p.getIndividualAttack();
}
},
IV_DEFENSE("Def", ColumnType.INT, CellRendererHelper.IV) {
@Override
public Object get(final Pokemon p) {
return p.getIndividualDefense();
}
},
IV_STAMINA("Stam", ColumnType.INT, CellRendererHelper.IV) {
@Override
public Object get(final Pokemon p) {
return p.getIndividualStamina();
}
},
TYPE_1("Type 1", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return PokemonUtils.formatType(p.getSettings().getType());
}
},
TYPE_2("Type 2", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return PokemonUtils.formatType(p.getSettings().getType2());
}
},
MOVE_1("Move 1", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return PokemonUtils.formatMove(p.getMove1())
+ PokemonUtils.formatDps(PokemonCalculationUtils.dpsForMove(p, true));
}
},
MOVE_2("Move 2", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return PokemonUtils.formatMove(p.getMove2())
+ PokemonUtils.formatDps(PokemonCalculationUtils.dpsForMove(p, false));
}
},
DPS_1("DPS 1", ColumnType.DPS1VALUE) {
@Override
public Object get(final Pokemon p) {
return Math.round(10.0 * PokemonCalculationUtils.dpsForMove(p, true)) / 10.0;
}
},
DPS_2("DPS 2", ColumnType.DPS2VALUE) {
@Override
public Object get(final Pokemon p) {
return Math.round(10.0 * PokemonCalculationUtils.dpsForMove(p, false)) / 10.0;
}
},
MOVETYPE_1("Movetype 1", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
final PokemonMove move = p.getMove1();
PokemonType type = PokemonMeta.getMoveSettings(move).getPokemonType();
return PokemonUtils.formatType(type);
}
},
MOVETYPE_2("Movetype 2", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
final PokemonMove move = p.getMove2();
PokemonType type = PokemonMeta.getMoveSettings(move).getPokemonType();
return PokemonUtils.formatType(type);
}
},
HP("HP", ColumnType.INT) {
@Override
public Object get(final Pokemon p) {
return p.getMaxStamina();
}
},
EVOLVABLE_COUNT("Evolvable", ColumnType.NULLABLE_INT) {
@Override
public Object get(final Pokemon p) {
if (p.getCandiesToEvolve() > 1) {
final int candies = p.getCandy();
final int candiesToEvolve = p.getCandiesToEvolve();
int evolvable = (int) ((double) candies / candiesToEvolve);
int rest = candies % candiesToEvolve;
final boolean transferAfterEvolve = ConfigNew.getConfig().getBool(ConfigKey.TRANSFER_AFTER_EVOLVE);
// We iterate and get how many candies are added while evolving and if that can make up for some more evolves
int newEvolvable = evolvable;
do {
final int candyGiven = newEvolvable + (transferAfterEvolve ? newEvolvable : 0);
newEvolvable = (int) ((double) (candyGiven + rest) / candiesToEvolve);
evolvable = evolvable + newEvolvable;
rest = (candyGiven + rest) % candiesToEvolve;
} while (newEvolvable > 0);
return String.valueOf(evolvable);
} else {
return StringLiterals.NO_VALUE_SIGN;
}
}
},
CANDIES("Candies", ColumnType.INT) {
@Override
public Object get(final Pokemon p) {
return p.getCandy();
}
},
CANDIES_TO_EVOLVE("To Evolve", ColumnType.NULLABLE_INT) {
@Override
public Object get(final Pokemon p) {
if (p.getCandiesToEvolve() != 0) {
return String.valueOf(p.getCandiesToEvolve());
} else {
return StringLiterals.NO_VALUE_SIGN;
}
}
},
STARDUST_TO_POWERUP("Stardust", ColumnType.INT) {
@Override
public Object get(final Pokemon p) {
return p.getStardustCostsForPowerup();
}
},
MAX_CP_CUR("Max CP (Cur)", ColumnType.INT) {
@Override
public Object get(final Pokemon p) {
try {
return p.getMaxCpForPlayer();
} catch (NoSuchItemException e) {
return -1;
}
}
},
MAX_CP_40("Max CP (40)", ColumnType.INT) {
@Override
public Object get(final Pokemon p) {
try {
return p.getMaxCp();
} catch (NoSuchItemException e) {
return -1;
}
}
},
MAX_CP_EVOLVED_CUR("Max CP Evolved (Cur)", ColumnType.INT) {
@Override
public Object get(final Pokemon p) {
final List<PokemonIdOuterClass.PokemonId> highest = Evolutions.getHighest(p.getPokemonId());
final PokemonIdOuterClass.PokemonId highestUpgradedFamily = highest.get(0);
return p.getMaxCpFullEvolveAndPowerupForPlayer(highestUpgradedFamily);
}
},
MAX_CP_EVOLVED_40("Max CP Evolved (40)", ColumnType.INT) {
@Override
public Object get(final Pokemon p) {
final List<PokemonIdOuterClass.PokemonId> highest = Evolutions.getHighest(p.getPokemonId());
final PokemonIdOuterClass.PokemonId highestUpgradedFamily = highest.get(0);
return p.getCpFullEvolveAndPowerup(highestUpgradedFamily);
}
},
CP_EVOLVED("CP Evolved", ColumnType.NULLABLE_INT) {
@Override
public Object get(final Pokemon p) {
final List<PokemonIdOuterClass.PokemonId> highest = Evolutions.getHighest(p.getPokemonId());
final PokemonIdOuterClass.PokemonId highestUpgradedFamily = highest.get(0);
final int cpAfterFullyEvolve;
if (highest.contains(p.getPokemonId())) {
cpAfterFullyEvolve = p.getCp();
} else {
cpAfterFullyEvolve = p.getCpAfterFullEvolve(highestUpgradedFamily);
}
if (cpAfterFullyEvolve != p.getCp()) {
return String.valueOf(cpAfterFullyEvolve);
} else {
return StringLiterals.NO_VALUE_SIGN;
}
}
},
CAUGHT_WITH("Caught With", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return PokemonUtils.formatItem(p.getPokeball());
}
},
CAUGHT_TIME("Caught Time", ColumnType.DATE) {
@Override
public Object get(final Pokemon p) {
return DateHelper.toString(DateHelper.fromTimestamp(p.getCreationTimeMs()));
}
},
FAVORITE("Favorite", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return (p.isFavorite()) ? YES : "";
}
},
GYM("Gym", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return (p.isDeployed()) ? YES : "";
}
},
DUEL_ABILITY_RATING("Duel Ability Rating", ColumnType.PERCENTAGE) {
@Override
public Object get(final Pokemon p) {
return Utilities.percentage(PokemonCalculationUtils.duelAbility(p), PokemonPerformanceCache.getStats(p.getPokemonId()).duelAbility.value);
}
},
GYM_OFFENSE_RATING("Gym Offense Rating", ColumnType.PERCENTAGE) {
@Override
public Object get(final Pokemon p) {
return Utilities.percentage(PokemonCalculationUtils.gymOffense(p), PokemonPerformanceCache.getStats(p.getPokemonId()).gymOffense.value);
}
},
GYM_DEFENSE_RATING("Gym Defense Rating", ColumnType.PERCENTAGE) {
@Override
public Object get(final Pokemon p) {
return Utilities.percentage(PokemonCalculationUtils.gymDefense(p), PokemonPerformanceCache.getStats(p.getPokemonId()).gymDefense.value);
}
},
DUEL_ABILITY("Duel Ability", ColumnType.PERCENTAGE) {
@Override
public Object get(final Pokemon p) {
return Utilities.percentage(PokemonCalculationUtils.duelAbility(p), PokemonPerformanceCache.getHighestStats().duelAbility.value);
}
},
GYM_OFFENSE("Gym Offense", ColumnType.PERCENTAGE) {
@Override
public Object get(final Pokemon p) {
return Utilities.percentage(PokemonCalculationUtils.gymOffense(p), PokemonPerformanceCache.getHighestStats().gymOffense.value);
}
},
GYM_DEFENSE("Gym Defense", ColumnType.PERCENTAGE) {
@Override
public Object get(final Pokemon p) {
return Utilities.percentage(PokemonCalculationUtils.gymDefense(p), PokemonPerformanceCache.getHighestStats().gymDefense.value);
}
},
MOVE_1_RATING("Move 1 Rating", ColumnType.PERCENTAGE) {
@Override
public Object get(final Pokemon p) {
return PokemonCalculationUtils.moveRating(p, true);
}
},
MOVE_2_RATING("Move 2 Rating", ColumnType.PERCENTAGE) {
@Override
public Object get(final Pokemon p) {
return PokemonCalculationUtils.moveRating(p, false);
}
},
CAUGHT_COORDINATES("Caught Coordinates", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
final S2CellId cell = new S2CellId(p.getCapturedS2CellId());
final int locationDecimals = 6;
return LocationHelper.getCoordinates(cell).toString(locationDecimals);
}
},
CAUGHT_CITY("Caught City", ColumnType.FUTURE_STRING) {
@Override
public Object get(final Pokemon p) {
final S2CellId cell = new S2CellId(p.getCapturedS2CellId());
return LocationHelper.getLocation(cell).thenApply(location -> location.city);
}
},
CAUGHT_LOCATION("Caught Location", ColumnType.FUTURE_STRING) {
@Override
public Object get(final Pokemon p) {
final S2CellId cell = new S2CellId(p.getCapturedS2CellId());
return LocationHelper.getLocation(cell).thenApply(location -> location.formattedLocation);
}
},
COSTUME("Costume", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return p.getPokemonDisplay() != null ? p.getPokemonDisplay().getCostume().toString() : "";
}
},
GENDER("Gender", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return p.getPokemonDisplay() != null ? p.getPokemonDisplay().getGender().toString() : "";
}
},
SHINY("Shiny", ColumnType.STRING) {
@Override
public Object get(final Pokemon p) {
return p.getPokemonDisplay() != null ? (p.getPokemonDisplay().getShiny() ? YES : "")
: "";
}
},
PID("PID", ColumnType.LONG) {
@Override
public Object get(final Pokemon p) {
return p.getId();
}
};
private static final String YES = "Yes";
public final int id;
public final String heading;
public final ColumnType columnType;
public final ArrayList data;
private TableCellRenderer customCellRenderer;
/**
* Constructor to create the enum entries.
*
* @param heading The name of the column.
* @param columnType The type of the column.
*/
PokeColumn(final String heading, final ColumnType columnType) {
this.id = Internal.AUTO_INCREMENTER.get();
this.heading = heading;
this.columnType = columnType;
this.data = CollectionHelper.provideArrayList(columnType.clazz);
}
/**
* Constructor to create an enum entry with a custom cell renderer.
*
* @param heading The name of the column.
* @param columnType The type of the column.
* @param customCellRenderer The custom cell renderer.
*/
PokeColumn(final String heading, final ColumnType columnType, final TableCellRenderer customCellRenderer) {
this(heading, columnType);
this.customCellRenderer = customCellRenderer;
}
/**
* Gets the PokeColumn enum for given id.
*
* @param id The id.
* @return The column.
*/
public static PokeColumn getForId(final int id) {
for (final PokeColumn column : PokeColumn.values()) {
if (column.id == id) {
return column;
}
}
// If not found, we throw an exception
throw new NoSuchElementException("There is no column with id " + id);
}
/**
* Gets the PokeColumn enum for given heading.
*
* @param heading The heading.
* @return The column.
*/
public static PokeColumn getForHeading(final String heading) {
for (final PokeColumn column : PokeColumn.values()) {
if (column.heading.equals(heading)) {
return column;
}
}
// If not found, we throw an exception
throw new NoSuchElementException("There is no column with heading " + heading);
}
/**
* Returns the comparator for the given column, based on the column type.
*
* @return The comparator.
*/
public Comparator getComparator() {
return columnType.comparator;
}
/**
* Returns the table cell renderer for the given column, based on the column type.
*
* @return The cell renderer.
*/
public TableCellRenderer getCellRenderer() {
return customCellRenderer != null ? customCellRenderer : columnType.tableCellRenderer;
}
/**
* This method must be overwritten and should return what should be the
* data that has to be displayed.
*
* @param p The Pokémon that of that row.
* @return The data that has to be displayed
*/
public abstract Object get(Pokemon p);
/**
* We need an wrapper for the auto-incrementer here, so that we can access it statically.
*/
private static class Internal {
static final AutoIncrementer AUTO_INCREMENTER = new AutoIncrementer();
}
}