package vooga.rts.networking.client;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.logging.Level;
import javax.swing.JPanel;
import util.logger.LoggerManager;
import vooga.rts.networking.NetworkBundle;
import vooga.rts.networking.client.clientgui.ClientViewAdapter;
import vooga.rts.networking.client.clientgui.IModel;
import vooga.rts.networking.communications.ExpandedLobbyInfo;
import vooga.rts.networking.communications.IMessage;
import vooga.rts.networking.communications.LobbyInfo;
import vooga.rts.networking.communications.PlayerInfo;
import vooga.rts.networking.communications.TimeStamp;
import vooga.rts.networking.communications.UserTimeStamp;
import vooga.rts.networking.communications.clientmessages.ClientTimingMessage;
import vooga.rts.networking.communications.clientmessages.InitialConnectionMessage;
import vooga.rts.networking.communications.clientmessages.JoinLobbyMessage;
import vooga.rts.networking.communications.clientmessages.LeaveLobbyMessage;
import vooga.rts.networking.communications.clientmessages.ReadyToStartGameMessage;
import vooga.rts.networking.communications.clientmessages.RequestServerListMessage;
import vooga.rts.networking.communications.clientmessages.RequestStartGameMessage;
import vooga.rts.networking.communications.clientmessages.StartLobbyMessage;
import vooga.rts.networking.communications.clientmessages.UpdateLobbyInfoMessage;
import vooga.rts.networking.communications.servermessages.ServerInfoMessage;
/**
* Model for the overall server browser on the client.
*
* @author Sean Wareham
* @author Henrique Morales
* @author David Winegar
*
*/
public class ClientModel extends Observable implements IClientModel, IModel {
private static final int ONE_SECOND = 1000;
private static final int NANOSECONDS_IN_MILLISECOND = 1000000000;
private IClient myClient;
private String myUserName;
private ExpandedLobbyInfo myLobbyInfo;
private List<PlayerInfo> myUserControlledPlayers = new ArrayList<PlayerInfo>();
private PlayerInfo myPlayer;
private NetworkedGame myGame;
private ClientViewAdapter myViewAdapter;
private List<String> myFactions;
private long myTimeDelay;
/**
* This is the handler of information needed by all of the views in the process of connecting to
* / creating a server, creating a game, waiting in a lobby.
*
* @param game game that called us
* @param gameName name of the game
* @param userName name of the user
* @param factionNameList a list of all faction choices, in string form
* @param mapNameList a list of all map names
* @param maxPlayerList a list of all max players. Should be the same length as the mapNameList
* and contain an Integer value for the max players corresponding to the position that
* the mapNameList.
*/
public ClientModel (NetworkedGame game,
String gameName,
String userName,
List<String> factionNameList,
List<String> mapNameList,
List<Integer> maxPlayerList) {
myGame = game;
myFactions = factionNameList;
myUserName = userName;
myClient = new Client(this);
IMessage initialConnection = new InitialConnectionMessage(gameName, userName);
myClient.sendMessage(initialConnection);
myViewAdapter = new ClientViewAdapter(this, gameName, mapNameList, maxPlayerList);
//testPing();
}
private void testPing () {
myTimeDelay = System.nanoTime();
myClient.sendMessage(new ClientTimingMessage(new UserTimeStamp(myTimeDelay)));
}
@Override
public void setTimeDelay (TimeStamp timeStamp) {
timeStamp.stamp(System.nanoTime());
// divide in 2 for round trip
myTimeDelay = timeStamp.getDifference() / NANOSECONDS_IN_MILLISECOND / 2;
}
@Override
public void getMessage (IMessage message) {
if (message instanceof ServerInfoMessage) {
((ServerInfoMessage) message).affectClient(this);
}
}
@Override
public void closeConnection () {
myClient.closeConnection();
}
/**
* Request currently available lobbies from the server
*/
public void requestLobbies () {
myClient.sendMessage(new RequestServerListMessage());
}
/**
* Request to join a lobby on the server
*
* @param id ID of the lobby to join
*/
public void requestJoinLobby (int id) {
myClient.sendMessage(new JoinLobbyMessage(id));
}
/**
* Request to leave a lobby on the server
*/
public void leaveLobby () {
myLobbyInfo.removePlayer(myPlayer);
myClient.sendMessage(new LeaveLobbyMessage(myLobbyInfo));
}
/**
* Starts a new lobby for purposes of hosting a game
*
* @param lobbyInfo Lobby containing information to host a game
*/
public void startLobby (LobbyInfo lobbyInfo) {
myClient.sendMessage(new StartLobbyMessage(lobbyInfo));
}
/**
* Request to initiate the game in this lobby
*/
public void requestStartGame () {
myClient.sendMessage(new RequestStartGameMessage());
}
/**
* Sends an infoLobby so other users can view that the state of
* the lobby has changed
*/
public void sendUpdatedLobbyInfo () {
myClient.sendMessage(new UpdateLobbyInfoMessage(myLobbyInfo));
}
/**
* Gets the panel that this model's view uses.
* @return the view used by all networking functions
*/
public JPanel getView () {
return myViewAdapter.getView();
}
@Override
public void addLobbies (LobbyInfo[] lobbies) {
myViewAdapter.changeLobbies(lobbies);
}
@Override
public void updateFaction (String faction, int position) {
myLobbyInfo.getPlayerAtPosition(position).setFaction(faction);
sendUpdatedLobbyInfo();
}
@Override
public void updateTeam (int team, int position) {
myLobbyInfo.getPlayerAtPosition(position).setTeam(team);
sendUpdatedLobbyInfo();
}
@Override
public void switchToLobby (ExpandedLobbyInfo lobbyInfo, int playerID) {
myPlayer = new PlayerInfo(myUserName, 1, myFactions.get(0), playerID);
myUserControlledPlayers.clear();
myUserControlledPlayers.add(myPlayer);
lobbyInfo.addPlayer(myPlayer);
myViewAdapter.switchToLobbyView(lobbyInfo);
}
@Override
public void updateLobby (ExpandedLobbyInfo lobbyInfo) {
myLobbyInfo = lobbyInfo;
myViewAdapter.updateLobby();
}
@Override
public void alertClient (String title, String message) {
myViewAdapter.alertClient(title, message);
}
@Override
public void loadGame (ExpandedLobbyInfo lobbyInfo) {
myGame.loadGame(lobbyInfo, myPlayer);
myClient.sendMessage(new ReadyToStartGameMessage());
}
@Override
public void startGame () {
try {
Thread.sleep(ONE_SECOND - myTimeDelay);
}
catch (InterruptedException e) {
LoggerManager.DEFAULT_LOGGER.log(Level.SEVERE, NetworkBundle.getString("WaitFailed"));
}
myGame.startGame(myClient);
}
/**
*
* @return LobbyInfo of this model
*/
public ExpandedLobbyInfo getLobbyInfo () {
return myLobbyInfo;
}
/**
*
* @return List with player information for this lobby
*/
public List<PlayerInfo> getPlayersInfo () {
return myUserControlledPlayers;
}
/**
*
* @return A list with name of factions of this client view
*/
public List<String> getFactions () {
return myFactions;
}
@Override
public void connectionClosed () {
getView().removeAll();
myGame.serverBrowserClosed();
}
}