package onlinefrontlines.lobby;
import java.util.Calendar;
import java.sql.SQLException;
import onlinefrontlines.Constants;
import onlinefrontlines.Army;
import onlinefrontlines.auth.User;
import onlinefrontlines.auth.UserCache;
import onlinefrontlines.feedback.FeedbackDAO;
import onlinefrontlines.userstats.*;
import onlinefrontlines.utils.Tools;
import onlinefrontlines.utils.CacheException;
/**
* A user that is active / has conquered a country in a lobby
*
* @author jorrit
*
* Copyright (C) 2009-2013 Jorrit Rouwe
*
* This file is part of Online Frontlines.
*
* Online Frontlines is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Online Frontlines is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Online Frontlines. If not, see <http://www.gnu.org/licenses/>.
*/
public class LobbyUser
{
/**
* Lobby we belong to
*/
public LobbyState lobbyState;
/**
* User id
*/
public final int userId;
/**
* Cached user name
*/
public final String cachedUsername;
/**
* Army of user (can change for users that have not selected their army yet)
*/
public Army army = Army.none;
/**
* If user is still connected
*/
private boolean isConnected = false;
/**
* Last time communication was received (to time out user and kick him from the lobby)
*/
private long lastCommunicationTime;
/**
* Country that the user is defending
*/
private Country defendedCountry;
/**
* Country that the user is attacking
*/
private Country attackedCountry;
/**
* Indicates when the user is linked to an attacked / defended country
* if he still needs to accept the challenge or not
*/
public boolean hasAcceptedChallenge;
/**
* If current time passes this time (in millis) the challenge is no longer valid and the user should be removed
* from the country
*/
public long challengeValidUntil;
/**
* Cached rank
*/
public int rank = 0;
/**
* Cached level
*/
public int level = 0;
/**
* Cached leaderboard position
*/
public int leaderboardPosition = 0;
/**
* Cached feedback score
*/
public int feedbackScore = 0;
/**
* Number of games won
*/
public int gamesWon = 0;
/**
* Number of games lost
*/
public int gamesLost = 0;
/**
* Cached from user
*/
public boolean autoDefendOwnedCountry;
public boolean autoDeclineFriendlyDefender;
/**
* Counter that indicates when this user was last changed
*/
public int changeCount = 0;
/**
* Constructor
*/
public LobbyUser(LobbyState lobbyState, User user)
{
this.lobbyState = lobbyState;
this.userId = user.id;
this.cachedUsername = user.username;
try
{
updateUserInfoInternal();
}
catch (CacheException e)
{
Tools.logException(e);
}
catch (SQLException e)
{
Tools.logException(e);
}
}
/**
* Get user
*/
public User getUser() throws CacheException
{
return UserCache.getInstance().get(userId);
}
/**
* Update user info without writing changes to the db
*
* @return True if user info changed
*/
private boolean updateUserInfoInternal() throws CacheException, SQLException
{
boolean modified = false;
// Cache user
User user = getUser();
// Determine army
if (user.army != Army.none && army != user.army)
{
// Update army
army = user.army;
modified = true;
// Cancel pending actions
setCountries(null, null);
}
// Determine feedback score
int tempFeedbackScore = FeedbackDAO.getScore(userId);
if (feedbackScore != tempFeedbackScore)
{
feedbackScore = tempFeedbackScore;
modified = true;
}
// Determine if user auto defends
boolean autodef = user.autoDefendOwnedCountry;
if (autoDefendOwnedCountry != autodef)
{
autoDefendOwnedCountry = autodef;
modified = true;
}
// Determine if user auto declines friendly matches
boolean autodecline = user.autoDeclineFriendlyDefender;
if (autoDeclineFriendlyDefender != autodecline)
{
autoDeclineFriendlyDefender = autodecline;
modified = true;
}
// Determine stats
UserStats stats = UserStatsCache.getInstance().get(userId);
if (stats != null)
{
if (gamesWon != stats.gamesWon)
{
gamesWon = stats.gamesWon;
modified = true;
}
if (gamesLost != stats.gamesLost)
{
gamesLost = stats.gamesLost;
modified = true;
}
int tempRank = UserRank.getRank(userId);
if (rank != tempRank)
{
rank = tempRank;
modified = true;
}
int tempLevel = UserRank.getLevel(userId);
if (level != tempLevel)
{
level = tempLevel;
modified = true;
}
}
// Determine leaderboard position
int tempLeaderboardPosition = 0;
UserLeaderboard board = UserLeaderboardCache.getInstance().get(UserLeaderboardCache.BOARD_TOTAL_POINTS);
UserLeaderboard.Entry entry = board.getEntry(userId);
if (entry != null)
tempLeaderboardPosition = entry.position;
if (leaderboardPosition != tempLeaderboardPosition)
{
leaderboardPosition = tempLeaderboardPosition;
modified = true;
}
return modified;
}
/**
* Update user information from the database
*/
public void updateUserInfo() throws SQLException, CacheException
{
// Call internal function
boolean modified = updateUserInfoInternal();
// Notify any change
if (modified)
lobbyState.notifyLobbyUserChanged(this);
}
/**
* Check if a user is still connected
*/
public boolean getIsConnected()
{
return isConnected;
}
/**
* Called when communication is received from the user
*/
public void markConnected()
{
lastCommunicationTime = Calendar.getInstance().getTime().getTime();
if (!isConnected)
{
isConnected = true;
lobbyState.notifyLobbyUserChanged(this);
}
}
/**
* Check if user connection timed out
*/
public void checkConnectedTimeOut()
{
// Check timeout
if (isConnected
&& Calendar.getInstance().getTime().getTime() - lastCommunicationTime > Constants.CLIENT_POLL_TIMEOUT)
{
// No longer connected
isConnected = false;
lobbyState.notifyLobbyUserChanged(this);
}
}
/**
* Check if user can be removed from the list of users
*/
public boolean canBeRemoved()
{
return !isConnected
&& Calendar.getInstance().getTime().getTime() - lastCommunicationTime > 3 * Constants.CLIENT_POLL_TIMEOUT
&& defendedCountry == null
&& attackedCountry == null
&& !lobbyState.isUserOnMap(userId);
}
/**
* Set country to defend and attack
*/
public void setCountries(Country defendedCountry, Country attackedCountry)
{
// Check NOP
if (defendedCountry == this.defendedCountry
&& attackedCountry == this.attackedCountry)
return;
// Unlink from countries
if (this.defendedCountry != null)
{
assert(this.defendedCountry.defender == this);
this.defendedCountry.defender = null;
}
if (this.attackedCountry != null)
{
assert(this.attackedCountry.attacker == this);
this.attackedCountry.attacker = null;
}
// Link to new countries
if (defendedCountry != null)
{
assert(defendedCountry.army == army);
assert(defendedCountry.defender == null);
defendedCountry.defender = this;
}
if (attackedCountry != null)
{
assert(attackedCountry.army != army);
assert(attackedCountry.attacker == null);
attackedCountry.attacker = this;
}
// Set pointers
this.defendedCountry = defendedCountry;
this.attackedCountry = attackedCountry;
// Reset other flags
if (defendedCountry == null || attackedCountry == null)
{
hasAcceptedChallenge = false;
challengeValidUntil = 0;
}
// Flag update
lobbyState.invalidateDefendableCountries();
}
/**
* Access to the currently defended country
*/
public Country getDefendedCountry()
{
return defendedCountry;
}
/**
* Access to the currently attacked country
*/
public Country getAttackedCountry()
{
return attackedCountry;
}
/**
* Get location of challenged country
*/
public int getDefendedCountryX()
{
return defendedCountry != null? defendedCountry.locationX : -1;
}
public int getDefendedCountryY()
{
return defendedCountry != null? defendedCountry.locationY : -1;
}
/**
* Get location of challenged country
*/
public int getAttackedCountryX()
{
return attackedCountry != null? attackedCountry.locationX : -1;
}
public int getAttackedCountryY()
{
return attackedCountry != null? attackedCountry.locationY : -1;
}
/**
* Get state string for communication with Flash application
*/
@Override
public String toString()
{
return userId + "," + Tools.flashEscape(cachedUsername) + "," + Army.toInt(army) + "," + (isConnected? 1 : 0) + "," + getDefendedCountryX() + "," + getDefendedCountryY() + "," + getAttackedCountryX() + "," + getAttackedCountryY() + "," + (hasAcceptedChallenge? 1 : 0) + "," + rank + "," + level + "," + leaderboardPosition + "," + feedbackScore + "," + gamesWon + "," + gamesLost + "," + (autoDefendOwnedCountry? 1 : 0) + "," + (autoDeclineFriendlyDefender? 1 : 0);
}
}