package ch.bfh.jass.model;
import ch.bfh.jass.exceptions.GameNotExistsException;
import ch.bfh.jass.exceptions.UserAlreadyExistsException;
import ch.bfh.jass.game.Game;
import ch.bfh.jass.interfaces.IPlayer;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.*;
import java.util.*;
import sun.misc.BASE64Encoder;
/**
* @author David Baumgartner <baumd9@bfh.ch>, Fabian Schneider <schnf6@bfh.ch>
* @version 1.0
*/
public class EntityManager {
private static EntityManager currentInstance;
private Connection conn = null;
private Map<String, User> userMap;
private Map<String, Game> gameMap;
private int gameIdCounter = 0;
/**
* Private Class Constructor
*/
private EntityManager() {
conn = null;
try {
String userName = "root";
String password = "";
String url = "jdbc:mysql://localhost/jass";
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn = DriverManager.getConnection(url, userName, password);
System.out.println("Database connection established");
} catch (Exception e) {
System.err.println("Cannot connect to database server" + e.toString());
}
userMap = new HashMap<String, User>();
gameMap = new HashMap<String, Game>();
}
/**
* Returns a current instance
*
* @return
*/
public static EntityManager getCurrentInstance() {
if (currentInstance == null) {
currentInstance = new EntityManager();
}
return currentInstance;
}
/**
* @return all games in the map
*/
public Map<String, Game> getGames() {
return Collections.unmodifiableMap(gameMap);
}
/**
* Loads a user in the entity manager.
*
* @param username
* @return
* @throws SQLException
*/
public User getUser(String username) throws SQLException {
if (userMap.containsKey(username)) {
return userMap.get(username);
} else {
User user = accessUser(username);
if (user != null) {
userMap.put(username, user);
}
return user;
}
}
/**
* Creates a new user. Proofs if the user already exists.
*
* @param username
* @param password
* @param fullName
* @return
* @throws SQLException
* @throws UserAlreadyExistsException
*/
public User createNewUser(String username, String password, String fullName) throws SQLException, UserAlreadyExistsException {
User oldUser = getUser(username);
if (oldUser != null) {
throw new UserAlreadyExistsException("User already Exists");
} else {
PreparedStatement s;
String sql = "INSERT INTO `user` (`user_id` ,`username` ,`password` ,`fullname` )VALUES (NULL , ?, ?, ?)";
s = conn.prepareStatement(sql);
s.setString(1, username);
s.setString(2, hashMD5(password));
s.setString(3, fullName);
s.executeUpdate();
s.close();
return getUser(username);
}
}
/**
* Loads a user from the database.
*
* @param username
* @return
* @throws SQLException
*/
private User accessUser(String username) throws SQLException {
Statement s = conn.createStatement();
s.executeQuery("SELECT user_id, username, password, fullname FROM user where username='" + username + "'");
ResultSet rs = s.getResultSet();
int count = 0;
User res = null;
while (rs.next()) {
int userID = rs.getInt("user_id");
String username2 = rs.getString("username");
String password = rs.getString("password");
String fullName = rs.getString("fullname");
res = new User(userID, username, password, fullName);
System.out.println("id = " + userID + ", name = " + username2 + ", fullname = " + fullName);
++count;
}
rs.close();
s.close();
System.out.println(count + " rows were retrieved");
return res;
}
/**
* Adds a game.
*
* @param game
*/
public void addGame(Game game) {
String gameID = "Game" + (++this.gameIdCounter);
game.setGameID(gameID);
this.gameMap.put(gameID, game);
}
/**
* Returns the game by specified ID.
*
* @param id
* @return
* @throws GameNotExistsException
*/
public Game getGameByID(String id) throws GameNotExistsException {
if (gameMap.containsKey(id)) {
return this.gameMap.get(id);
} else {
throw new GameNotExistsException("This game doesn't exist.");
}
}
/**
* Hashes a string md5 and encode to base64.
*
* @param message
* @return
*/
public String hashMD5(String message) {
MessageDigest msgDigest;
String hashValue = null;
try {
msgDigest = MessageDigest.getInstance("MD5");
msgDigest.update(message.getBytes("UTF-8"));
byte rawByte[] = msgDigest.digest();
hashValue = (new BASE64Encoder()).encode(rawByte);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Something went really wrong! " + e.getMessage());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Something went really wrong! " + e.getMessage());
}
return hashValue;
}
/**
* Write Game Results
*
* @param game
* @throws SQLException
*/
public void writeGameResults(Game game) throws SQLException {
if (gameMap.containsValue(game)) {
this.gameMap.remove(game.getGameID());
int gameID = getGameID();
List<List<IPlayer>> teams = game.getTeams();
PreparedStatement s;
String insertUserTeam = "INSERT INTO `user_team` (`team_id` ,`user_id` ,`points` ) VALUES (?, ?, ?)";
String insertGameTeam = "INSERT INTO `game_team` (`game_id` ,`team_id` ) VALUES (?, ?)";
for (List<IPlayer> team : teams) {
int teamID = getTeamID();
for (IPlayer player : team) {
String username = player.getUsername();
s = conn.prepareStatement(insertUserTeam);
s.setInt(1, teamID);
s.setInt(2, getUser(username).getUserID());
s.setInt(3, player.getPoints());
s.executeUpdate();
s.close();
}
s = conn.prepareStatement(insertGameTeam);
s.setInt(1, gameID);
s.setInt(2, teamID);
s.executeUpdate();
s.close();
}
}
}
/**
* Returns a team by a specified ID.
*
* @return
* @throws SQLException
*/
public int getTeamID() throws SQLException {
Statement s = conn.createStatement();
s.executeQuery("SELECT MAX( team_id ) AS max_team_id FROM `user_team`");
ResultSet rs = s.getResultSet();
int teamid = 1;
if (rs != null && rs.next()) {
teamid += rs.getInt("max_team_id");
}
s.close();
return teamid;
}
/**
* Returns a game by a specified ID.
*
* @return
* @throws SQLException
*/
public int getGameID() throws SQLException {
Statement s = conn.createStatement();
s.executeQuery("SELECT MAX( game_id ) AS max_game_id FROM `game_team`");
ResultSet rs = s.getResultSet();
int gameid = 1;
if (rs != null && rs.next()) {
gameid += rs.getInt("max_game_id");
}
s.close();
return gameid;
}
/**
* Removes a game.
*
* @param game
*/
public void removeGame(Game game) {
if (gameMap.containsValue(game)) {
this.gameMap.remove(game.getGameID());
}
}
/**
* Returns all games played by a user.
*
* @param user
* @return
* @throws SQLException
*/
public List<FinishedGame> getGameHistoryByUser(User user) throws SQLException {
Statement s1 = conn.createStatement();
s1.execute("Select game_id FROM user_team INNER JOIN game_team ON user_team.team_id = game_team.team_id WHERE user_id = " + user.getUserID() + " ORDER BY game_id DESC");
ResultSet rs1 = s1.getResultSet();
List<FinishedGame> gameHistory = new ArrayList<FinishedGame>();
while (rs1.next()) {
Statement s2 = conn.createStatement();
s2.execute("Select * FROM user_team INNER JOIN game_team ON user_team.team_id = game_team.team_id WHERE game_id=" + rs1.getInt("game_id"));
ResultSet rs2 = s2.getResultSet();
FinishedGame finishedGame = new FinishedGame(rs1.getInt("game_id"), user);
while (rs2.next()) {
HistoryPlayer resultUser = this.getHistoryPlayer(rs2.getInt("user_id"));
resultUser.setPoints(rs2.getInt("points"));
finishedGame.addPlayer(resultUser, rs2.getInt("team_id"));
}
gameHistory.add(finishedGame);
}
return gameHistory;
}
/**
* Returns a history player.
*
* @param userID
* @return
* @throws SQLException
*/
private HistoryPlayer getHistoryPlayer(int userID) throws SQLException {
for (User user : this.userMap.values()) {
if (user.getUserID() == userID) {
return new HistoryPlayer(userID, user.getUsername());
}
}
User user = this.accessUserByID(userID);
if (user != null) {
userMap.put(user.getUsername(), user);
}
return new HistoryPlayer(userID, user.getUsername());
}
/**
* Loads a user from the database.
*
* @param userID
* @return
* @throws SQLException
*/
private User accessUserByID(int userID) throws SQLException {
Statement s = conn.createStatement();
s.executeQuery("SELECT user_id, username, password, fullname FROM user where user_id='" + userID + "'");
ResultSet rs = s.getResultSet();
int count = 0;
User res = null;
while (rs.next()) {
String username = rs.getString("username");
String password = rs.getString("password");
String fullName = rs.getString("fullname");
res = new User(userID, username, password, fullName);
System.out.println("id = " + userID + ", name = " + username + ", fullname = " + fullName);
++count;
}
rs.close();
s.close();
System.out.println(count + " rows were retrieved");
return res;
}
}