package kakuro.server;
import java.io.*;
import java.util.*;
import kakuro.table.ITable;
import kakuro.table.Position;
import kakuro.table.TableException;
import kakuro.gui.Gui;
import kakuro.server.hintfactory.*;
import kakuro.server.tablefactory.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/** Szerver osztály. A grafikus kliens innen kapja az összes adatot. Nem túl nagy munkával át lehet alakítani
* igazi több-klienses hálózatos játékká, ha igény lenne rá. */
public class Server implements IServer {
/** Adatbázis kapcsolat */
private Connection con = null;
/** Statement a lekérdezésekhez */
private Statement stmt = null;
/** PreparedStatement lekérdezésekhez, gyorsabb verzió */
private PreparedStatement ps = null;
/** lekérdezés string */
private String query;
/** sikeres volt a login */
private boolean login_succes;
/** sikeres volt a regisztrálás */
private boolean regist_succes;
/** SQL kapcsolat paraméterei, adatbázis neve, helye, driver stb. */
static private Properties sqlProperties;
/** Gui a visszahíváshoz */
private Gui _gui = null;
/** Az SQL kapcsolat paramétereit beolvassa egy properties fileból */
static {
try {
sqlProperties = new Properties();
sqlProperties.load(new FileInputStream("sql.properties"));
sqlProperties.list(System.out);
} catch (IOException ioe) {
System.out.println("SQL properties file not found, using default hardcoded values!");
}
}
/** Szerver konstruktor, felépíti az adatbázis kapcsolatot is. */
public Server() {
createConnection();
}
/** Bejelentkezés.
*
* @param nick név
* @param password jelszó
* @param gui grafikus felület a visszahíváshoz
* @return felhasználó példány, ha létezik
* */
public User login(String nick, String password, Gui gui) throws ServerException {
/*if (con==null) {
return new User("00000", nick, "Admin".equalsIgnoreCase(nick), "Guest".equalsIgnoreCase(nick));
}*/
if (con==null) {
gui.showMessage("Database connection isnt working properly!");
return null;
}
_gui = gui;
boolean nick_exists = false;
boolean password_ok = false;
boolean isAdmin = false;
login_succes = true;
String id = "00000";
if ((nick.equals("Guest") == false) && (password.equals("guestjelszo") == false)){
try{
query = "SELECT USERID, USERNICKNAME, USERPASSWORD, UserAdmin FROM user WHERE USERNICKNAME = ? ";
ps = (PreparedStatement) con.prepareStatement(query);
ps.setString(1, nick);
ResultSet rs = ps.executeQuery();
while (rs.next()){
id = rs.getString("USERID");
String s1 = rs.getString("USERNICKNAME");
String s2 = rs.getString("USERPASSWORD");
isAdmin = rs.getBoolean("UserAdmin");
if (s1.equals(nick) == true){
nick_exists = true;
if (s2.equals(password) == true){
password_ok = true;
}
}
}
if (nick_exists == true){
if (password_ok == true){
_gui.showMessage("Sikeresen bejelentkeztel!");
}else{
_gui.debug("Wrong password !");
_gui.showMessage("Rossz jelszo!");
login_succes = false;
}
}else{
_gui.debug("Rossz nev!");
_gui.showMessage("Rossz nev!");
login_succes = false;
}
rs.close();
} catch (SQLException se) {
se.printStackTrace();
_gui.debug("Login failed with "+se.getLocalizedMessage());
}
}
return new User(id, nick, isAdmin, nick.equalsIgnoreCase("Guest"));
}
/** Sikerült-e a login */
public boolean getLoginSucces(){
return login_succes;
}
/** Sikerült-e a regisztrálás */
public boolean getRegistSucces(){
return regist_succes;
}
/** Regisztrálás
*
* @param gui gui a visszahíváshoz
* @param name név
* @param email email cím
* @param nick becenév
* @param passw1 jelszó1
* @param passw2 jelszó2
* */
public void register(Gui gui, String name, String email, String nick, String passw1, String passw2) throws ServerException {
boolean nick_used = false;
int row = 0;
_gui = gui;
regist_succes = true;
try{
query = "SELECT max(UserID) as maxid FROM user";
ResultSet rs = stmt.executeQuery(query);
if (rs.next()){
row = rs.getInt("maxid");
}
rs.close();
query = "SELECT USERNICKNAME FROM user";
rs = stmt.executeQuery(query);
if ((name.equals("") == false) && (email.equals("") == false) && (nick.equals("") == false) && (passw1.equals("") == false) && (passw2.equals("") == false)){
while (rs.next()){
String s = rs.getString("USERNICKNAME");
if (s.equals(nick) == true)
nick_used = true;
}
rs.close();
if (nick_used == false){
if (passw1.equals(passw2) == false){
_gui.debug("The two passwords aren't match!!");
_gui.showMessage("A ket jelszo nem egyezik!");
regist_succes = false;
}else{
query = "INSERT INTO user VALUES(?,?,?,?,?,0)";
PreparedStatement ps = (PreparedStatement) con.prepareStatement(query);
ps.setString(1, integerToString(row+1,5));
ps.setString(2, name);
ps.setString(3, email);
ps.setString(4, nick);
ps.setString(5, passw1);
ps.executeUpdate();
_gui.showMessage("Sikeresen regisztraltal\nes beleptel a jatekba!");
}
}else{
_gui.debug("This nickname is already in use!! Please choose another nickname !");
_gui.showMessage("Ez a nev mar foglalt!\nValassz masikat!");
regist_succes = false;
}
}else{
_gui.debug("Some data is missing !");
_gui.showMessage("Some data is missing !");
regist_succes = false;
}
} catch (SQLException se) {
se.printStackTrace();
_gui.debug("Register failed with "+se.getLocalizedMessage());
}
}
/** Számot stringgé alakít, az elejér megfelelő számú nullát rak
*
* @param nr szám
* @param length hossz
* */
public String integerToString(int nr, int length){
String s = null;
StringBuilder sb = new StringBuilder();
s = Integer.toString(nr);
for(int i = length; i > s.length(); i--){
sb.append('0');
}
sb.append(nr);
s = sb.toString();
return s;
}
/** A kapott ResultSet sorból összerak egy Skeletont.
*
* @param rs ResultSet sor, a tables táblából
* @return kész skeleton
* */
protected ISkeletonTable getSkeleton(ResultSet rs) throws SQLException {
final String[] s = new String[5];
s[0] = rs.getString("TABLEID");
s[1] = rs.getString("TABLEDIFFICULTY");
s[2] = rs.getString("TABLEROWS");
s[3] = rs.getString("TABLECOLUMNS");
s[4] = rs.getString("TABLECONTENT");
int dif = Integer.parseInt(s[1]);
int cols = Integer.parseInt(s[3]);
int rows = Integer.parseInt(s[2]);
HashMap<Position, Boolean> map = new HashMap<Position, Boolean>();
for (int i=0; i<rows; i++) {
for (int j=0; j<cols; j++) {
if (s[4].charAt((i*cols)+j)=='B') map.put(new Position(j, i), true);
}
}
System.out.println("loading "+rs.getInt("TableId"));
return new SkeletonTableImpl(map, rows, cols, dif, rs.getInt("TableId"));
}
/** Leellenőrzi, hogy az adott Skeleton ábrázolásban van-e túl hosszú szó */
public boolean checkSkeleton(String content,int row,int col){
boolean res = false;
int c1 = 0;
int c2 = 0;
char[][] matrix1 = new char[row][col];
char[][] matrix2 = new char[col][row];
int i,j;
for(i = 0;i < row;i++){
for(j = 0;j < col;j++){
matrix1[i][j] = content.charAt((i*col)+j);
if (matrix1[i][j] == 'W'){
c1++;
}else
c1 = 0;
if (c1 > 9) c2++;
}
}
for(i = 0;i < col;i++){
for(j = 0;j < row;j++){
matrix2[i][j] = content.charAt((i*row)+j);
if (matrix2[i][j] == 'W'){
c1++;
}else
c1 = 0;
if (c1 > 9) c2++;
}
}
res = (c2 == 0);
return res;
}
/** Skeletonok listázása.
*
* @param listType ha true, akkor mindent listáz, ha false, akkor csak a jó skeletonokat
* */
public List<ISkeletonTable> listSkeletonTables(boolean listType) {
List<ISkeletonTable> result = new ArrayList<ISkeletonTable>();
try{
query = "SELECT * FROM tables";
ResultSet rs = stmt.executeQuery(query);
String content = null;
int row = 0;
int col = 0;
while (rs.next()){
if (listType == true){
result.add(getSkeleton(rs));
}else{
content = rs.getString("TABLECONTENT");
row = Integer.parseInt(rs.getString("TABLEROWS"));
col = Integer.parseInt(rs.getString("TABLECOLUMNS"));
if (checkSkeleton( content, row, col)){
result.add(getSkeleton(rs));
}
}
}
rs.close();
} catch (SQLException se) {
se.printStackTrace();
_gui.debug("Register failed with "+se.getLocalizedMessage());
}
return result;
}
/** Új játék indítása, idő nulláról indul */
public Session startNewGame(User user, ITable table) {
return new Session(user, table, 0);
}
/** Mentett játék indítása, idő a mentett időtől indul */
public Session startLoadedGame(User user, ITable table) {
long time = 0;
try{
String sql = "SELECT GameTime FROM game where game.UserID='"+user.getID()+"' and TableID='"+integerToString(table.getSkeletonId(), 8)+"'";
ResultSet set = stmt.executeQuery(sql);
while (set.next()){
time = set.getLong("GameTime");
}
set.close();
} catch (SQLException se) {
_gui.debug("Start loaded games failed with "+se.getLocalizedMessage());
}
return new Session(user, table, time);
}
/** Játék vége jelzés a szerver felé. Bekerülhet a highscore-ba, ha nem csalt és jó az idő. */
public void stopGame(Session session) {
String id = session.getUser().getID();
ITable table = session.getTable();
long timespent = session.getTimeSpent();
try{
if ((session.isCheater() == false) && (session.getUser().isGuest() == false)){
ResultSet set2= null;
if ((table.getDifficulty() == ITable.DIFFICULTY_HARD)){
set2 = stmt.executeQuery("select UserAdmin from user where user.UserID='"+id+"'");
boolean ua = set2.getBoolean("UserAdmin");
if (ua == false){
_gui.showMessage("grat, admin jogot szereztel !\nMostantol szerkeszthetsz tablakat !");
stmt.executeUpdate("update user set UserAdmin = 1 where user.UserID='"+id+"'");
session.getUser().setAdmin(true);
_gui.setRights();
}
}
set2 = null;
set2 = stmt.executeQuery("SELECT stats.* FROM stats join tables on tables.TableID=stats.TableID where tables.TableDifficulty="+table.getDifficulty());
int i = 0;
Long[] times = new Long[] {0l,0l,0l,0l,0l};
while( (set2.next()) && (i < 5) ){
times[i] = set2.getLong("GameTime");
i++;
}
List<Long> timeList = Arrays.asList(times);
Collections.sort(timeList);
for(i = 0; i < 5; i++) times[i] = Long.parseLong(timeList.get(i).toString());
i = 0;
while((i < 5) && (times[i] != 0) && (times[i] <= timespent)){
i++;
}
if(i == 0){
stmt.executeUpdate("insert into stats values('"+id+"', '"+integerToString(table.getSkeletonId(), 8)+"', "+timespent+", "+null+")");
_gui.showMessage("grat, bekerultel a highscoreba !");
}
if((i < 5) && (times[i] >= timespent)){
stmt.executeUpdate("update stats set UserID = '"+id+"', TableID = '"+integerToString(table.getSkeletonId(), 8)+"', GameTime = "+timespent+", GameDate = "+null+" where GameTime = "+Long.toString(times[4]));
_gui.showMessage("grat, bekerultel a highscoreba !");
}
if(i == 5){
_gui.showMessage("Sajna ez az ido tul keves ahhoz,\nhogy bekerulj a highscore-ba");
}
}
} catch (SQLException se) {
se.printStackTrace();
_gui.debug("Stop game failed with "+se.getLocalizedMessage());
_gui.showMessage("Stop game failed !");
}
catch (Throwable t) {
t.printStackTrace();
}
}
/** Játék mentése */
public void saveGame(Session session) throws TableException {
_gui.debug("Saving...");
String id = session.getUser().getID();
ITable table = session.getTable();
long timespent = session.getTimeSpent();
String content = "";
int x = table.getColumnCount();
int y = table.getRowCount();
for (int j = 0; j < y; j++) {
for (int i = 0; i < x; i++) {
Position pos = new Position(i, j);
switch (table.getType(pos)) {
case ITable.BLACK_NONE:
{
content = content + "-|-";
break;
}
case ITable.BLACK_VERTICAL:
{
int vsum = table.getSum(pos, ITable.SUM_VERTICAL);
content = content + integerToString(vsum,2) + "/-";
break;
}
case ITable.BLACK_HORIZONTAL:
{
int hsum = table.getSum(pos, ITable.SUM_HORIZONTAL);
content = content + "-/" + integerToString(hsum,2);
break;
}
case ITable.BLACK_BOTH:
{
int vsum = table.getSum(pos, ITable.SUM_VERTICAL);
int hsum = table.getSum(pos, ITable.SUM_HORIZONTAL);
content = content + integerToString(vsum,2) + "/" + integerToString(hsum,2);
break;
}
case ITable.WHITE:
{
int normalValue = table.readCell(pos, ITable.VALUE_NORMAL);
int trueValue = table.readCell(pos, ITable.VALUE_TRUE);
content = content + integerToString(normalValue,1) + "=" + integerToString(trueValue,1);
break;
}
}
if((j == y-1) && (i == x-1))
content = content + ';';
else
content = content + ',';
}
}
try{
stmt.executeUpdate("delete from game where game.UserID='"+session.getUser().getID()+"' and TableID='"+integerToString(table.getSkeletonId(), 8)+"'");
query = "INSERT INTO game VALUES(?,?,?,?)";
PreparedStatement ps = (PreparedStatement) con.prepareStatement(query);
ps.setString(1, id);
ps.setString(2, integerToString(session.getTable().getSkeletonId(), 8));
ps.setString(3, ""+timespent);
ps.setString(4, content);
ps.executeUpdate();
_gui.showMessage("Jatek mentes sikeres!");
} catch (SQLException se) {
se.printStackTrace();
_gui.debug("Saving failed with "+se.getLocalizedMessage());
_gui.showMessage("Save was failed !");
}
}
/** Skeleton mentése */
public void saveSkeleton(ISkeletonTable skeleton) {
String content = "";
int difficulty = skeleton.getDifficulty();
int x = skeleton.getColumnCount();
int y = skeleton.getRowCount();
for (int j = 0; j < y; j++) {
for (int i = 0; i < x; i++) {
Position pos = new Position(i, j);
switch (skeleton.getType(pos)) {
case ISkeletonTable.CELL_BLACK:
{
content = content + "B";
break;
}
case ISkeletonTable.CELL_WHITE:
{
content = content + "W";
break;
}
}
}
}
int row = 0;
try{
query = "SELECT max(TableID) as maxid FROM tables";
ResultSet rs = stmt.executeQuery(query);
if (rs.next()){
row = rs.getInt("maxid");
}
rs.close();
System.out.println("saving at "+row);
query = "INSERT INTO tables VALUES(?,?,?,?,?)";
PreparedStatement ps = (PreparedStatement) con.prepareStatement(query);
ps.setString(1, integerToString(row+1, 8));
ps.setString(2, Integer.toString(difficulty));
ps.setString(3, Integer.toString(y));
ps.setString(4, Integer.toString(x));
ps.setString(5, content);
ps.executeUpdate();
} catch (SQLException se) {
se.printStackTrace();
_gui.debug("Saving failed with "+se.getLocalizedMessage());
}
}
/** Játéktábla mentett állapotát alakítja át mátrixos alakra */
private int[][] getMatrixValues(String s, int rows, int cols, boolean user) {
int[][] result = new int[cols][rows];
String[] split = s.split("[,;]");
int x, y;
for (int i=0; i<split.length; i++) {
String t = split[i];
x = i%cols;
y = i/cols;
System.out.println("at ["+x+","+y+"]: "+t);
if (t.contains("=")) {
String[] p = t.split("=");
result[x][y] = Integer.parseInt(p[user?1:0]);
}
}
return result;
}
/** Felhasználóhoz tartozó mentett állások listázása */
public List<ITable> listSavedGames(User user) {
List<ITable> result = new ArrayList<ITable>();
HashMap<Integer, ISkeletonTable> skeletonMap = new HashMap<Integer, ISkeletonTable>();
try{
String sql = "SELECT tables.* FROM tables join game on game.TableID=tables.TableID where game.UserID='"+user.getID()+"'";
System.out.println(sql);
ResultSet set = stmt.executeQuery(sql);
while (set.next()){
ISkeletonTable st = getSkeleton(set);
skeletonMap.put(st.getId(), st);
}
set.close();
sql = "SELECT * FROM game where UserID='"+user.getID()+"'";
System.out.println(sql);
set = stmt.executeQuery(sql);
while (set.next()) {
ISkeletonTable skellie = skeletonMap.get(set.getInt("TableID"));
int[][] written = getMatrixValues(set.getString("GameContent"), skellie.getRowCount(), skellie.getColumnCount(), true);
int[][] actual = getMatrixValues(set.getString("GameContent"), skellie.getRowCount(), skellie.getColumnCount(), false);
result.add(new GeneralTable(skellie, written, actual));
}
set.close();
if (result.size()<1) _gui.showMessage("Nincs mentett jatekod!");
} catch (SQLException se) {
se.printStackTrace();
_gui.debug("List saved games failed with "+se.getLocalizedMessage());
}
return result;
}
/** Skeleton kitöltése számokkal */
public ITable populateSkeleton(ISkeletonTable skeleton) {
return BipartiteTableFactory.getInstance().populateSkeleton(skeleton);
}
/** Tábla generálása a nehézségi szintnek megfelelően */
public ITable generateTable(int skillLevel) {
return BipartiteTableFactory.getInstance().generateTable(skillLevel);
}
/** Skeleton generálás a nehézségi szintnek megfelelően */
public ISkeletonTable generateSkeleton(int skillLevel) {
return BipartiteTableFactory.getInstance().generateSkeleton(skillLevel);
}
/** Highscore lista lekérés nehézségi szint szerint */
public TreeMap<Integer, String> listHighscore(int difficulty) {
TreeMap<Integer, String> result = new TreeMap<Integer, String>();
try{
String tid = null;
String un = null;
ResultSet set = stmt.executeQuery("SELECT stats.*, user.UserName FROM stats join tables on tables.TableID=stats.TableID join user on user.UserID=stats.UserID where tables.TableDifficulty="+difficulty);
while(set.next()){
tid = set.getString("GameTime");
un = set.getString("UserName");
result.put(Integer.parseInt(tid), un);
}
} catch (SQLException se) {
se.printStackTrace();
_gui.debug("Saving failed with "+se.getLocalizedMessage());
_gui.showMessage("Save failed !");
}
return result;
}
/** Tippek legenerálása */
public void generateHints() {
HintFactory.getInstance().generateHints();
}
/** Tipp lekérése
*
* @param sum összeg
* @param cellCount szóhossz
* @return tippek listája
* */
public Iterator<String> getHint(int sum, int cellCount) {
return HintFactory.getInstance().getHint(sum, cellCount);
}
/** SQL kapcsolatot építi fel. Ha van sql.properties file, akkor onnan szedi a paramétereket,
* ha nem létezik, akkor használja a beégetett fix mysql paramétereket. */
public void createConnection() {
try {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
super.run();
System.out.println("Sql shutdown started, closing connection");
try {
if (stmt != null) {
if (sqlProperties.getProperty("DBDRIVER", "com.mysql.jdbc.Driver").contains("hsqldb")) {
System.out.println("Shutting down properly the hsqldb database...");
stmt.execute("SHUTDOWN");
}
stmt.close();
} if (con != null)
con.close();
} catch (Throwable t) {
t.printStackTrace();
}
System.out.println("Sql shutdown hook end");
}
});
Class.forName(sqlProperties.getProperty("DBDRIVER", "com.mysql.jdbc.Driver")).newInstance();
con = DriverManager.getConnection(sqlProperties.getProperty("DBURL", "jdbc:mysql://localhost/kakuro"),
sqlProperties.getProperty("DBUSER", "kakuro"), sqlProperties.getProperty("DBPASSWD", "jelszo"));
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from user");
while (rs.next()) {
System.out.println("User/password - isAdmin: "+rs.getString("UserName")+"/"+rs.getString("UserPassword")+" - "+rs.getBoolean("UserAdmin"));
}
rs.close();
} catch (Exception e) {
e.printStackTrace();
if (_gui != null){
_gui.debug("Sql connection isn't working properly: " +e.getLocalizedMessage());
}
}
}
}