package org.pokenet.server.backend.entity;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import org.pokenet.server.GameServer;
import org.pokenet.server.backend.entity.TradeOffer.TradeType;
import org.pokenet.server.battle.DataService;
import org.pokenet.server.battle.Pokemon;
import org.pokenet.server.battle.PokemonEvolution;
import org.pokenet.server.battle.PokemonSpecies;
import org.pokenet.server.battle.PokemonEvolution.EvolutionTypes;
import org.pokenet.server.network.MySqlManager;
/**
* A trade between two players
* @author shadowkanji
*
*/
public class Trade implements Runnable{
/* Stores the offers */
private HashMap<Tradeable, TradeOffer[]> m_offers;
public boolean m_isExecuting = false;
private ArrayList<String> m_queries = new ArrayList<String>();
/**
* Constructor
* @param player1
* @param player2
*/
public Trade(Tradeable player1, Tradeable player2) {
m_offers = new HashMap<Tradeable, TradeOffer[]>();
m_offers.put(player1, null);
m_offers.put(player2, null);
/* Block players of same IP address from trading */
if(player1.getIpAddress().equalsIgnoreCase(player2.getIpAddress())) {
if(player1 instanceof PlayerChar) {
PlayerChar p = (PlayerChar) player1;
p.getTcpSession().write("!Trading cannot be done with that player");
}
endTrade();
return;
}
if(player1 instanceof PlayerChar) {
/* Tell the client to open the trade window */
PlayerChar p = (PlayerChar) player1;
Char c = (Char) player2;
p.getTcpSession().write("Ts" + c.getName());
/*
* Send the pokemon data of player 2 to player 1
*/
Pokemon[] player2Party = player2.getParty();
for(int i = 0; i < player2Party.length; i++) {
if(player2Party[i] != null) {
p.getTcpSession().write("Ti" + i + PokemonSpecies.getDefaultData().getPokemonByName(player2Party[i].getSpeciesName()).getSpeciesNumber() + "," +
player2Party[i].getName() + "," +
player2Party[i].getHealth() + "," +
player2Party[i].getGender() + "," +
(player2Party[i].isShiny() ? 1 : 0) + "," +
player2Party[i].getStat(0) + "," +
player2Party[i].getStat(1) + "," +
player2Party[i].getStat(2) + "," +
player2Party[i].getStat(3) + "," +
player2Party[i].getStat(4) + "," +
player2Party[i].getStat(5) + "," +
player2Party[i].getTypes()[0] + "," +
(player2Party[i].getTypes().length > 1 &&
player2Party[i].getTypes()[1] != null ? player2Party[i].getTypes()[1] + "," : ",") +
player2Party[i].getExp() + "," +
player2Party[i].getLevel() + "," +
player2Party[i].getAbilityName() + "," +
player2Party[i].getNature().getName() + "," +
(player2Party[i].getMoves()[0] != null ? player2Party[i].getMoves()[0].getName() : "") + "," +
(player2Party[i].getMoves()[1] != null ? player2Party[i].getMoves()[1].getName() : "") + "," +
(player2Party[i].getMoves()[2] != null ? player2Party[i].getMoves()[2].getName() : "") + "," +
(player2Party[i].getMoves()[3] != null ? player2Party[i].getMoves()[3].getName() : ""));
}
}
}
if(player2 instanceof PlayerChar) {
/* If player 2 is a PlayerChar, tell client to open trade window */
PlayerChar p = (PlayerChar) player2;
Char c = (Char) player1;
p.getTcpSession().write("Ts" + c.getName());
/*
* Send the Pokemon data of player 1 to player 2
*/
Pokemon[] player1Party = player1.getParty();
for(int i = 0; i < player1Party.length; i++) {
if(player1Party[i] != null) {
p.getTcpSession().write("Ti" + i + PokemonSpecies.getDefaultData().getPokemonByName(player1Party[i].getSpeciesName()).getSpeciesNumber() + "," +
player1Party[i].getName() + "," +
player1Party[i].getHealth() + "," +
player1Party[i].getGender() + "," +
(player1Party[i].isShiny() ? 1 : 0) + "," +
player1Party[i].getStat(0) + "," +
player1Party[i].getStat(1) + "," +
player1Party[i].getStat(2) + "," +
player1Party[i].getStat(3) + "," +
player1Party[i].getStat(4) + "," +
player1Party[i].getStat(5) + "," +
player1Party[i].getTypes()[0] + "," +
(player1Party[i].getTypes().length > 1 &&
player1Party[i].getTypes()[1] != null ? player1Party[i].getTypes()[1] + "," : ",") +
player1Party[i].getExp() + "," +
player1Party[i].getLevel() + "," +
player1Party[i].getAbilityName() + "," +
player1Party[i].getNature().getName() + "," +
(player1Party[i].getMoves()[0] != null ? player1Party[i].getMoves()[0].getName() : "") + "," +
(player1Party[i].getMoves()[1] != null ? player1Party[i].getMoves()[1].getName() : "") + "," +
(player1Party[i].getMoves()[2] != null ? player1Party[i].getMoves()[2].getName() : "") + "," +
(player1Party[i].getMoves()[3] != null ? player1Party[i].getMoves()[3].getName() : ""));
}
}
}
}
/**
* Sets the offer from a player
* @param p
* @param o
*/
public void setOffer(Tradeable t, int poke, int money) {
if(t instanceof PlayerChar) {
PlayerChar p = (PlayerChar) t;
if(p.getMoney() < money)
return;
}
TradeOffer [] o = new TradeOffer[2];
o[0] = new TradeOffer();
o[0].setId(poke);
o[0].setType(TradeType.POKEMON);
o[0].setInformation(t.getParty()[poke].getSpeciesName());
if(poke > -1 && poke < 6) {
if(!DataService.canTrade(t.getParty()[poke].getSpeciesName())) {
endTrade();
return;
}
}
o[1] = new TradeOffer();
o[1].setQuantity(money);
o[1].setType(TradeType.MONEY);
m_offers.put(t, o);
/* Send the offer to the other player */
sendOfferInformation(t, o);
}
/**
* Cancels an offer from a player
* @param p
*/
public void cancelOffer(Tradeable t) {
Iterator<Tradeable> it = m_offers.keySet().iterator();
Tradeable otherPlayer = null;
/* Find the other player */
while(it.hasNext()) {
Tradeable temp = it.next();
if(temp != t) {
otherPlayer = temp;
}
}
/* Check the other player hasn't accepted a previous offer */
if(!otherPlayer.acceptedTradeOffer()) {
m_offers.put(t, null);
otherPlayer.receiveTradeOfferCancelation();
}
}
/**
* Sends offer information from one player to another
* @param p
* @param poke
* @param money
*/
private void sendOfferInformation(Tradeable t, TradeOffer [] o) {
Iterator<Tradeable> i = m_offers.keySet().iterator();
while(i.hasNext()) {
Tradeable temp = i.next();
if(temp.getName().compareTo(t.getName()) != 0) {
temp.receiveTradeOffer(o);
}
}
}
/**
* Checks if both player's agree to trade
*/
public void checkForExecution() {
Iterator<Tradeable> i = m_offers.keySet().iterator();
if(i.next().acceptedTradeOffer() && i.next().acceptedTradeOffer()) {
try{
executeTrade();
} catch (Exception e){
e.printStackTrace();
}
}
}
/**
* Executes the trade
*/
private void executeTrade() {
/* Ensure two threads can't cause execute the trade */
if(!m_isExecuting) {
m_isExecuting = true;
Pokemon [] temp = new Pokemon[2];
Iterator<Tradeable> it = m_offers.keySet().iterator();
Tradeable player1 = it.next();
Tradeable player2 = it.next();
TradeOffer [] o1 = m_offers.get(player1);
TradeOffer [] o2 = m_offers.get(player2);
/* Ensure each player has made an offer */
if(o1 == null || o2 == null)
return;
/* Keep checking no player has left the trade */
if(player1 != null && player2 != null) {
/* Store a timestamp of the transaction */
Date date = new Date();
String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
/* Handle player 1's offers */
for(int j = 0; j < o1.length; j++) {
switch(o1[j].getType()) {
case POKEMON:
/*
* An id greater than 5 or less an 0 is sent
* if no pokemon is being traded
*/
if(o1[j].getId() >= 0 && o1[j].getId() <= 5) {
/* Store the Pokemon temporarily */
temp[0] = player1.getParty()[o1[j].getId()];
if(player1 instanceof PlayerChar && player2 instanceof PlayerChar) {
player1.getParty()[o1[j].getId()] = null;
m_queries.add("INSERT into pn_history (member,action,with,timestamp,details) VALUES ('"+((PlayerChar) player1).getId()+"','1','"+((PlayerChar)player2).getId()+"','"+timestamp+"','"+temp[0].getDatabaseID()+"')");
}
}
break;
case MONEY:
/* Ensure there was money offered */
if(o1[j].getQuantity() > 0) {
player1.setMoney(player1.getMoney() - o1[j].getQuantity());
player2.setMoney(player2.getMoney() + o1[j].getQuantity());
if(player1 instanceof PlayerChar && player2 instanceof PlayerChar) {
m_queries.add("INSERT into pn_history (member,action,with,timestamp,details) VALUES ('"+((PlayerChar) player1).getId()+"','0','"+((PlayerChar)player2).getId()+"','"+timestamp+"','"+o1[j].getQuantity()+"')");
}
}
break;
case ITEM:
break;
}
}
/* Handle player 2's offers */
for(int j = 0; j < o2.length; j++) {
switch(o2[j].getType()) {
case POKEMON:
/*
* An id greater than 5 or less an 0 is sent
* if no pokemon is being traded
*/
if(o2[j].getId() >= 0 && o2[j].getId() <= 5) {
/* Store the Pokemon temporarily */
temp[1] = player2.getParty()[o2[j].getId()];
if(player1 instanceof PlayerChar && player2 instanceof PlayerChar) {
player2.getParty()[o1[j].getId()] = null;
m_queries.add("INSERT into pn_history (member,action,with,timestamp,details) VALUES ('"+((PlayerChar) player2).getId()+"','1','"+((PlayerChar)player1).getId()+"','"+timestamp+"','"+temp[1].getDatabaseID()+"')");
}
}
break;
case MONEY:
/* Ensure there was money offered */
if(o2[j].getQuantity() > 0) {
player2.setMoney(player2.getMoney() - o2[j].getQuantity());
player1.setMoney(player1.getMoney() + o2[j].getQuantity());
if(player1 instanceof PlayerChar && player2 instanceof PlayerChar) {
m_queries.add("INSERT into pn_history (member,action,with,timestamp,details) VALUES ('"+((PlayerChar) player2).getId()+"','0','"+((PlayerChar)player1).getId()+"','"+timestamp+"','"+o2[j].getQuantity()+"')");
}
}
break;
case ITEM:
break;
}
}
/* Execute the Pokemon swap */
if(temp[1] != null) {
if(player1 instanceof PlayerChar) {
PlayerChar p = (PlayerChar) player1;
p.addPokemon(temp[1]);
}
}
if(temp[0] != null) {
if(player2 instanceof PlayerChar) {
PlayerChar p = (PlayerChar) player2;
p.addPokemon(temp[0]);
}
}
/* Evolution checks */
for (Pokemon curPokemon : temp) { // do both pokemon
PlayerChar p;
if(curPokemon == temp[0]){
p = (PlayerChar) player2;
} else {
p = (PlayerChar) player1;
}
int index = p.getPokemonIndex(curPokemon);
PokemonSpecies pokeData = PokemonSpecies.getDefaultData().getPokemonByName(
curPokemon.getSpeciesName());
for (PokemonEvolution currentEvolution : pokeData.getEvolutions()) {
System.out.println(curPokemon.getName() + " can evolve via " + currentEvolution.getType());
if (currentEvolution.getType().equals(EvolutionTypes.Trade)){
curPokemon.setEvolution(currentEvolution);
p.getTcpSession().write("PE" + index);
break;
} else if (currentEvolution.getType() == EvolutionTypes.TradeItem){
// TODO: trade item evolving
// need to check to see if they have the right item
break;
}
}
}
/* Update the money */
if(player1 instanceof PlayerChar) {
PlayerChar p = (PlayerChar) player1;
p.updateClientMoney();
}
if(player2 instanceof PlayerChar) {
PlayerChar p = (PlayerChar) player2;
p.updateClientMoney();
}
/* Store transactions on DB */
new Thread(this).start();
/* End the trade */
m_isExecuting = false;
endTrade();
}
}
}
/**
* Returns true if the trade was ended
*/
public boolean endTrade() {
if(!m_isExecuting) {
Iterator<Tradeable> i = m_offers.keySet().iterator();
while(i.hasNext()) {
Tradeable t = i.next();
if(t != null)
t.finishTrading();
}
m_offers.clear();
m_offers = null;
return true;
}
return false;
}
public void run() {
/*Record Trade on History Table*/
MySqlManager m_database = new MySqlManager();
if(m_database.connect(GameServer.getDatabaseHost(), GameServer.getDatabaseUsername(), GameServer.getDatabasePassword())){
m_database.selectDatabase(GameServer.getDatabaseName());
while(!m_queries.isEmpty()){
m_database.query(m_queries.get(0));
m_queries.remove(0);
}
}
m_database.close();
}
}