package server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import card.Card;
public abstract class ClientGame extends BaseGame {
public enum MSG_TYPES {ERROR, WARNING, INFORMATION, QUESTION};
//Options stuff
final File options = new File("options.json");
JSONObject optionsRoot;
int difficulty;
int fontSize;
Socket socket;
String hostName;
volatile boolean isConnected;
volatile boolean initGameReceived;
volatile int ownId; // TODO lock?
public ClientGame(){
preinit();
}
protected void preinit(){
port = 1337;
hostName = "localhost";
isConnected = false;
try {
socket = new Socket(hostName, port);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Thread(new SocketListenerThread(socket)).start();
while(!isConnected){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log("Waiting for connection to host");
}
Log("Connection to " + hostName + " on port " + port + " as player " + ownId + " established!");
while(!initGameReceived){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log("Client " + ownId + " waiting for game...");
}
}
@Override
protected void init() {
loadOptions();
loadFont();
super.init();
}
@Override
protected void createHistory() {
history = new ArrayList<>();
}
@Override
protected void createTrash() {
trash = new ArrayList<>();
}
protected void loadOptions(){
try {
JSONTokener tokener = new JSONTokener(new FileInputStream(options));
optionsRoot = new JSONObject(tokener);
difficulty = optionsRoot.getInt("difficulty");
fontSize = optionsRoot.getInt("fontSize");
if(difficulty < 0) difficulty = 0;
if(fontSize <= 0) fontSize = 20;
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
protected void movePlaceCard(Card c){
movePlaceCard(c, false);
}
protected void movePlaceCard(Card c, boolean isDry) {
byte msgType = isDry ? MOVE_PLACE_CARD | MOVE_DRY : MOVE_PLACE_CARD;
send(msgType, c.toJson().toString());
}
protected void moveTrashCard(Card c){
moveTrashCard(c, false);
}
protected void moveTrashCard(Card c, boolean isDry) {
byte msgType = isDry ? MOVE_TRASH_CARD | MOVE_DRY : MOVE_TRASH_CARD;
send(msgType, c.toJson().toString());
}
protected void moveHint(boolean isValue, int value, int playerId){
moveHint(isValue, value, playerId, false);
}
protected void moveHint(boolean isValue, int value, int playerId, boolean isDry){
byte msgType = isDry ? MOVE_HINT | MOVE_DRY : MOVE_HINT;
JSONObject msg = new JSONObject();
if(isValue){
msg.put("type", HINT_VALUE);
}
else {
msg.put("type", HINT_COLOR);
}
msg.put("value", value);
msg.put("playerId", playerId);
send(msgType, msg.toString());
}
protected void moveHint(Card c){
moveHint(c, false);
}
protected void moveHint(Card c, boolean isDry) {
byte msgType = isDry ? MOVE_HINT | MOVE_DRY : MOVE_HINT;
send(msgType, c.toJson().toString());
}
private void send(byte msgType, String msg) {
Log("Client - Sending to server");
Log("sending " + msg);
DataOutputStream os = null;
try {
os = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
os.write(MAGIC);
os.write(ServerGame.PROTOCOL.VIBE_DUMB.ordinal());
os.write(msgType);
os.write(new byte[]{ 0, 0 });
os.writeUTF(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//public abstract void printMessage(String msg, MSG_TYPES type);
protected abstract void createUi();
protected abstract void updateUi();
public int getDifficulty(){
return difficulty;
}
public abstract void loadFont();
public int getFontSize(){
return fontSize;
}
public Object getFont() {
// TODO
return null;
}
@Override
protected void receive(DataInputStream inStream) {
Log("Client - Received data!");
byte[] magic = new byte[4];
byte proto = 0;
byte msgType = 0;
byte[] useless = new byte[2];
try {
inStream.read(magic);
proto = inStream.readByte();
msgType = inStream.readByte();
inStream.read(useless);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log("Received magic: " + magic[0] + magic[1] + magic[2] + magic[3]);
Log("Received proto: " + proto);
Log("Received msgType: " + msgType);
Log("Received useless: " + useless[0] + useless[1]);
// TODO check Protocol
// switch(proto){
// case VIBE_DUMB:
// break;
// }
String msg = null;
JSONObject jo = null;
try {
msg = inStream.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO error handling
if(msg != null){
Log("The not null msg is: " + msg);
jo = new JSONObject(msg);
}
else return;
// TODO MOVE_DRY
switch(msgType){
case CONNECTION_VALID:
isConnected = true;
ownId = jo.getInt("id");
break;
case MOVE_UPDATE:
Log("received update");
if(!initGameReceived){
Log("first update!");
init();
updateGame(jo);
createUi();
initGameReceived = true;
break;
}
updateGame(jo);
updateUi();
break;
}
}
protected int getPlayersSightId(int id){
// TODO get the id of a player with ownId as 0-based index
return (id + (nPlayers - ownId)) % nPlayers;
}
protected int getRealId(int id){
// TODO get the real id of a player
return (id + ownId) % nPlayers;
}
protected void updateGame(JSONObject jo){
nPlayers = jo.getInt("nPlayers");
if(!initGameReceived){
createPlayers();
}
// TODO movesLeft = jo.getInt("movesLeft");
nCardsInDeck = jo.getInt("nCardsInDeck");
hints = jo.getInt("hints");
flashs = jo.getInt("flashs");
JSONArray trashArray = jo.getJSONArray("trash");
trash.clear(); // TODO depends on protocol version
for(int i=0; i<trashArray.length(); ++i){
JSONObject cardObject = trashArray.getJSONObject(i);
Card card = new Card(cardObject);
trash.add(card);
}
JSONObject deckRow = jo.getJSONObject("playingDeck");
for(int i=0; i<playingDeck.length; ++i){
JSONObject deckCol = deckRow.getJSONObject(String.valueOf(i));
for(int j=0; j<playingDeck[i].length; ++j){
playingDeck[i][j] = new Card(deckCol.getJSONObject(String.valueOf(j)));
}
}
JSONObject deckCounterObj = jo.getJSONObject("playingDeckCounter");
for(int i=0; i<playingDeckCounter.length; ++i){
playingDeckCounter[i] = deckCounterObj.getInt(String.valueOf(i));
}
JSONArray playerArray = jo.getJSONArray("players");
for(int i=0; i<players.length; ++i){
if(players[i] == null) players[i] = createPlayer(playerArray.getJSONObject(i));
players[i].setCards(playerArray.getJSONObject(i).getJSONArray("cards"));
}
currentPlayer = jo.getInt("currentPlayer");
}
}