package dekk.pw.pokemate.tasks;
import POGOProtos.Data.PokedexEntryOuterClass;
import POGOProtos.Inventory.Item.ItemIdOuterClass.ItemId;
import com.pokegoapi.api.inventory.Item;
import com.pokegoapi.api.inventory.ItemBag;
import com.pokegoapi.api.inventory.Pokeball;
import com.pokegoapi.api.map.pokemon.CatchResult;
import com.pokegoapi.api.map.pokemon.CatchablePokemon;
import com.pokegoapi.api.map.pokemon.encounter.EncounterResult;
import com.pokegoapi.api.pokemon.Pokemon;
import com.pokegoapi.exceptions.LoginFailedException;
import com.pokegoapi.exceptions.NoSuchItemException;
import com.pokegoapi.exceptions.RemoteServerException;
import dekk.pw.pokemate.*;
import dekk.pw.pokemate.util.StringConverter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import static POGOProtos.Networking.Responses.CatchPokemonResponseOuterClass.CatchPokemonResponse.CatchStatus.CATCH_SUCCESS;
/**
* Created by TimD on 7/21/2016.
*/
class CatchPokemon extends Task implements Runnable {
private static final Logger logger = LogManager.getLogger(CatchPokemon.class);
CatchPokemon(final Context context) {
super(context);
}
@Override
public void run() {
try {
List<CatchablePokemon> pokemon = context.getMap().getCatchablePokemon().stream()
.filter(this::shouldIgnore)
.collect(Collectors.toList());
if (pokemon.size() == 0) {
return;
}
Pokeball pokeball;
CatchResult catchResult;
for (CatchablePokemon target : pokemon) {
Walking.setLocation(context);
EncounterResult encounterResult = target.encounterPokemon();
if (!encounterResult.wasSuccessful()) {
continue;
}
//get pokedex entry.
PokedexEntryOuterClass.PokedexEntry entry = context.getApi().getInventories().getPokedex().getPokedexEntry(target.getPokemonId());
//if pokemon exist is registered in pokedex
if (entry != null) {
//need to get pokeball for each target in case there are no balls left of the last pokeball we used.
Item ball = itemBag().getItem(getItemForId(Config.getPreferredBall()));
if (ball != null && ball.getCount() > 0) {
pokeball = getBallForId(Config.getPreferredBall());
} else {
pokeball = target.getItemBall();
}
catchResult = target.catchPokemon(pokeball);
} else {
catchResult = target.catchPokemonWithBestBall();
}
if (catchResult.getStatus() != CATCH_SUCCESS) {
context.setConsoleString("CatchPokemon", target.getPokemonId() + "ran away.");
continue;
}
try {
final String targetId = target.getPokemonId().name();
pokemons().stream()
.filter(pkmn -> pkmn.getPokemonId().name().equals(targetId))
.sorted((a, b) -> Long.compare(b.getCreationTimeMs(), a.getCreationTimeMs()))
.findFirst()
.ifPresent(p -> {
String output = null;
try {
output = String.format("Caught a %s [CP: %d] [Candy: %d]", StringConverter.titleCase(targetId), p.getCp(), p.getCandy());
if (p.getCp() > Config.getMinimumCPForMessage()) {
PokeMateUI.toast(output, Config.POKE + "mon caught!", "icons/" + target.getPokemonId().getNumber() + ".png");
} else {
log(output + " [IV: " + getIvRatio(p) + "%]");
}
context.setConsoleString("CatchPokemon", String.format("%s [IV: %d%%]", output, getIvRatio(p)));
} catch (LoginFailedException e) {
logger.error("Login Failed", e);
} catch (RemoteServerException e) {
context.setConsoleString("CatchPokemon", "Server Error.");
logger.error("Remote Server Exception", e);
}
});
} catch (NullPointerException e) {
logger.error("NullPointerException.", e);
}
}
} catch (LoginFailedException e) {
logger.error("Login Failed", e);
} catch (RemoteServerException e) {
context.setConsoleString("CatchPokemon", "Server Error.");
logger.error("Remote Server Exception", e);
} catch (NoSuchItemException e) {
logger.error("Out of Pokeballs", e);
context.setConsoleString("CatchPokemon","Out of Pokeballs.");
} finally {
context.addTask(new CatchPokemon(context));
}
}
private boolean shouldIgnore(final CatchablePokemon p) {
return !Config.getIgnoreCatchingPokemon().contains(p.getPokemonId());
}
private List<Pokemon> pokemons() {
return context.getInventories().getPokebank().getPokemons();
}
private ItemBag itemBag() {
return context.getInventories().getItemBag();
}
private void log(final String message) {
final String formattedDate = new SimpleDateFormat("HH:mm:ss").format(new Date());
System.out.printf("[%s] - %s\n", formattedDate, message);
PokeMateUI.addMessageToLog(message);
}
private int getIvRatio(Pokemon pokemon) {
return (pokemon.getIndividualAttack() + pokemon.getIndividualDefense() + pokemon.getIndividualStamina()) * 100 / 45;
}
private ItemId getItemForId(final int id) {
return ItemId.forNumber(id);
}
private Pokeball getBallForId(int id) throws NoSuchItemException {
switch (id) {
case ItemId.ITEM_GREAT_BALL_VALUE:
return Pokeball.GREATBALL;
case ItemId.ITEM_ULTRA_BALL_VALUE:
return Pokeball.ULTRABALL;
case ItemId.ITEM_MASTER_BALL_VALUE:
return Pokeball.MASTERBALL;
case ItemId.ITEM_POKE_BALL_VALUE:
return Pokeball.POKEBALL;
default:
throw new NoSuchItemException();
}
}
}