package server;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
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;
// int port;
// String hostName;
Client client;
volatile boolean isConnected;
volatile boolean initGameReceived;
volatile int ownId; // TODO lock?
public ClientGame(Communicator comm) throws IOException{
preinit(comm);
}
protected void preinit(Communicator comm) throws IOException{
client = new Client(this, comm, -1);
client.comm.establish();
}
@Override
protected void init() {
loadOptions();
loadFont();
super.init();
}
@Override
protected void createHistory() {
history = new ArrayList<>();
}
@Override
protected void createTrash() {
trash = new ArrayList<>();
}
protected void sendReady() throws IOException {
try {
JSONObject jo = new JSONObject();
jo.put("origin", ownId);
Message m = new Message(jo);
m.setMsgType(Message.MAG_READY);
send(m);
} catch(JSONException ex) {
throw new InternalHanabiError(ex);
}
}
protected void sendUnReady() throws IOException {
try {
JSONObject jo = new JSONObject();
jo.put("origin", ownId);
Message m = new Message(jo);
m.setMsgType(Message.MSG_UNREADY);
send(m);
} catch(JSONException ex) {
throw new InternalHanabiError(ex);
}
}
protected void loadOptions(){
try {
Scanner optionsScanner = new Scanner(options, "UTF-8");
JSONTokener tokener = new JSONTokener(optionsScanner.useDelimiter("\\A").next());
optionsScanner.close();
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) throws IOException{
movePlaceCard(c, false);
}
protected void movePlaceCard(Card c, boolean isDry) throws IOException {
byte msgType = isDry ? Message.PLACE_CARD | Message.DRY : Message.PLACE_CARD;
send(msgType, c);
// send(msgType, c.toJson().toString());
}
protected void moveTrashCard(Card c) throws IOException{
moveTrashCard(c, false);
}
protected void moveTrashCard(Card c, boolean isDry) throws IOException {
byte msgType = isDry ? Message.TRASH_CARD | Message.DRY : Message.TRASH_CARD;
send(msgType, c);
// send(msgType, c.toJson().toString());
}
protected void moveHint(boolean isValue, int value, int playerId) throws IOException {
moveHint(isValue, value, playerId, false);
}
protected void moveHint(boolean isValue, int value, int playerId, boolean isDry) throws IOException {
byte msgType = isDry ? Message.HINT|Message.DRY : Message.HINT;
JSONObject msg = new JSONObject();
try {
if(isValue){
msg.put("type", Message.HINT_VALUE);
} else {
msg.put("type", Message.HINT_COLOR);
}
msg.put("value", value);
msg.put("playerId", playerId);
} catch(JSONException ex) {
throw new InternalHanabiError(ex);
}
send(msgType, msg);
// send(msgType, msg.toString());
}
protected void moveHint(Card c) throws IOException {
moveHint(c, false);
}
protected void moveHint(Card c, boolean isDry) throws IOException {
byte msgType = isDry ? Message.HINT|Message.DRY : Message.HINT;
send(msgType, c);
// send(msgType, c.toJson().toString());
}
private void send(byte msgType, Card c) throws IOException {
try {
send(msgType, c.toJson());
} catch(JSONException ex) {
throw new InternalHanabiError(ex);
}
}
private void send(byte msgType, JSONObject jo) throws IOException {
try {
jo.put("origin", ownId);
Message m = new Message(jo);
m.setMsgType(msgType);
send(m);
} catch(JSONException ex) {
throw new InternalHanabiError(ex);
}
}
private void send(Message m) throws IOException {
client.comm.sendMsg(m);
}
// private void send(byte msgType, String msg) {
// Utils.log(Utils.VERBOSE, "Client - Sending to server");
// Utils.log(Utils.VERBOSE, "sending " + msg);
// DataOutputStream os = null;
// try {
// os = new DataOutputStream(socket.getOutputStream());
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// try {
// os.write(Move.MAGIC);
// os.write(ServerGame.PROTO_VIBE_DUMB);
// 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) {
// Utils.log(Utils.VERBOSE, "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();
// }
//
// Utils.log(Utils.VERBOSE, "Received magic: " + magic[0] + magic[1] + magic[2] + magic[3]);
// Utils.log(Utils.VERBOSE, "Received proto: " + proto);
// Utils.log(Utils.VERBOSE, "Received msgType: " + msgType);
// Utils.log(Utils.VERBOSE, "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){
// Utils.log(Utils.VERBOSE, "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:
// Utils.log(Utils.VERBOSE, "received update");
// if(!initGameReceived){
// Utils.log(Utils.VERBOSE, "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;
}
private void updateGame(Message m) {
try {
updateGame(m.getJson());
} catch(JSONException ex) {
throw new InternalHanabiError(ex);
}
}
private void updateGame(JSONObject jo) throws JSONException {
nPlayers = jo.getInt("nPlayers");
if(!initGameReceived){
createPlayers();
}
// TODO movesLeft = jo.getInt("movesLeft");
nCardsInDeck = jo.getInt("nCardsInDeck");
hints = jo.getInt("hints");
flashs = jo.getInt("nFlashs");
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(new Message(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(new Message(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(new Message(playerArray.getJSONObject(i)));
players[i].setCards(playerArray.getJSONObject(i).getJSONArray("cards"));
}
currentPlayer = jo.getInt("currentPlayer");
}
protected void processMsg(Message m) {
// while(!isConnected){
// Utils.sleep(1000);
// Utils.log(Utils.VERBOSE, "Waiting for connection to host");
// }
Utils.log(Utils.VERBOSE, client.comm.getConnector().toString());
while(!initGameReceived){
Utils.sleep(1000);
Utils.log(Utils.VERBOSE, "Client " + ownId + " waiting for game...");
}
switch(m.getMsgType()){
case Message.MSG_CONNECTION_VALID:
isConnected = true;
ownId = m.getOwnId();
break;
case Message.UPDATE:
Utils.log(Utils.VERBOSE, "received update");
if(!initGameReceived){
Utils.log(Utils.VERBOSE, "first update!");
init();
updateGame(m);
createUi();
initGameReceived = true;
break;
}
updateGame(m);
updateUi();
break;
}
updateGame(m);
}
}