package server;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import org.json.JSONObject;
import org.json.JSONException;
import java.util.Arrays;
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;
}
}