package server;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import org.json.JSONObject;
import card.Card;
import card.CardInfo;
import player.BasePlayer;
import org.json.JSONArray;
import org.json.JSONException;
import java.util.Arrays;
import java.util.List;
public class VibeDumb implements Communicator {
public static final byte[] MAGIC = new byte[]{ 1, 3, 3, 7 };
private Connector conn;
private DataInputStream inStream;
private DataOutputStream outStream;
public VibeDumb(Connector c) {
conn = c;
}
public void sendMsg(Message m) throws IOException {
if(outStream == null) {
outStream = conn.getOutputStream();
}
byte version = 0;
byte msgType = m.getMsgType();
byte[] unused = new byte[]{ 0, 0 };
outStream.write(MAGIC);
outStream.write(version);
outStream.write(msgType);
outStream.write(unused);
if(msgType == Message.MSG_MOVE) outStream.writeUTF(moveToJsonString(m.getMove()));
else if(msgType == Message.MSG_CONNECTION_VALID) outStream.writeInt(m.getOwnId());
}
public Message receiveMsg() throws IOException {
if(inStream == null) {
inStream = conn.getInputStream();
}
byte[] magic = new byte[4];
byte version = 0;
byte msgType = 0;
byte[] unused = new byte[2];
inStream.read(magic);
if(!isMagicCorrect(magic)) {
throw new InternalHanabiError("Malformed message (wrong magic number).");
}
version = inStream.readByte();
switch(version) {
case 0: // TODO magic number?
break;
default:
throw new InternalHanabiError("Version " + version + " of protocol doesn't exist.");
}
msgType = inStream.readByte();
inStream.read(unused);
Message m = new Message(msgType);
if(msgType == Message.MSG_MOVE) {
String msg = inStream.readUTF(); // TODO ddos?
if(msg == null) throw new InternalHanabiError("Purported move doesn't exist.");
try {
m.setMove(jsonToMove(new JSONObject(msg)));
} catch(JSONException ex) {
throw new InternalHanabiError(ex);
}
} else if(msgType == Message.MSG_CONNECTION_VALID) {
m.setOwnId(inStream.readInt());
}
return m;
}
private static String moveToJsonString(Move move) {
try {
JSONObject jo = new JSONObject();
byte moveType = (byte) move.getMoveType();
jo.put(Keys.VibeDumb.MOVE_TYPE, moveType);
// TODO: dry moves
switch(moveType) {
case Move.HINT:
int type = move.getHintType();
jo.put(Keys.VibeDumb.HINT_TYPE, type);
if(type == Move.HINT_COLOR) {
jo.put(Keys.VibeDumb.COLOR, move.getColor());
} else if(type == Move.HINT_VALUE) {
jo.put(Keys.VibeDumb.VALUE, move.getValue());
} else {
throw new InternalHanabiError("Unknown hint type.");
}
break;
case Move.PLACE_CARD:
case Move.TRASH_CARD:
jo.put(Keys.VibeDumb.COLOR, move.getColor());
jo.put(Keys.VibeDumb.VALUE, move.getValue());
break;
default:
throw new InternalHanabiError("Move is neither hint nor place nor trash.");
}
return jo.toString();
} catch(JSONException ex) {
throw new InternalHanabiError(ex);
}
}
private static Move jsonToMove(JSONObject jo) {
try {
byte moveType = (byte)jo.getInt(Keys.VibeDumb.MOVE_TYPE);
Move move = new Move(moveType);
// TODO: dry moves
switch(moveType) {
case Move.HINT:
int type = jo.getInt(Keys.VibeDumb.HINT_TYPE);
move.setHintType(type);
if(type == Move.HINT_COLOR) {
move.setColor(jo.getInt(Keys.VibeDumb.COLOR));
} else if(type == Move.HINT_VALUE) {
move.setValue(jo.getInt(Keys.VibeDumb.VALUE));
} else {
throw new InternalHanabiError("Unknown hint type.");
}
break;
case Move.PLACE_CARD:
case Move.TRASH_CARD:
move.setColor(jo.getInt(Keys.VibeDumb.COLOR));
move.setValue(jo.getInt(Keys.VibeDumb.VALUE));
break;
default:
throw new InternalHanabiError("Move is neither hint nor place nor trash.");
}
return move;
} catch(JSONException ex) {
throw new InternalHanabiError(ex);
}
}
public void establish() throws IOException {
// FIXME
conn.establishConnection();
}
private static boolean isMagicCorrect(byte[] magic) {
return Arrays.equals(MAGIC, magic);
}
@Override
public Connector getConnector() {
return conn;
}
protected JSONObject serverGameToJson(ServerGame sg) throws JSONException {
JSONObject root = new JSONObject();
root.put("nCardsInDeck", sg.nCardsInDeck);
root.put("hints", sg.hints);
root.put("nFlashs", sg.flashs);
root.put("movesLeft", sg.movesLeft);
JSONArray trashArray = new JSONArray();
for(Card c : sg.trash){
trashArray.put(cardToJson(c));
}
root.put("trash", trashArray);
JSONObject deckRow = new JSONObject();
for(int i=0; i<sg.playingDeck.length; ++i){
JSONObject deckCol = new JSONObject();
for(int j=0; j<sg.playingDeck[i].length; ++j){
deckCol.put(String.valueOf(j), cardToJson(sg.playingDeck[i][j]));
//else deckCol.put(String.valueOf(j), new JSONObject());
}
deckRow.put(String.valueOf(i), deckCol);
}
root.put("playingDeck", deckRow);
JSONObject deckCounterObj = new JSONObject();
for(int i=0; i<sg.playingDeckCounter.length; ++i){
deckCounterObj.put(String.valueOf(i), sg.playingDeckCounter[i]);
}
root.put("playingDeckCounter", deckCounterObj);
JSONArray playerArray = new JSONArray();
for(BasePlayer p : sg.players){
playerArray.put(p.toJson());
}
root.put("players", playerArray);
root.put("currentPlayer", sg.currentPlayer);
root.put("nPlayers", sg.nPlayers);
return root;
}
public JSONObject cardToJson(Card c) throws JSONException {
// TODO: handle dummy card
JSONObject root = new JSONObject();
root.put("value", c.getValue());
root.put("id", c.getId());
root.put("color", c.getColor());
root.put("cardInfos", cardInfosToJson(c));
return root;
}
private JSONArray cardInfosToJson(Card c) throws JSONException {
JSONArray infoArray = new JSONArray();
List<CardInfo> cardInfos = c.getCardInfos();
if(cardInfos == null) return infoArray;
for(CardInfo ci : cardInfos){
infoArray.put(cardInfoToJson(ci));
}
return infoArray;
}
public JSONObject cardInfoToJson(CardInfo ci) throws JSONException {
JSONObject root = new JSONObject();
root.put("type", ci.getType());
root.put("is", ci.isIs());
root.put("what", ci.getWhat());
root.put("from", ci.getFrom());
return root;
}
// public Message jsonToMsg(JSONObject jo) throws JSONException {
// this.jo = jo; // TODO: clone?
// moveType = (byte)jo.getInt("msgType");
// }
}