package server;

import org.json.JSONObject;

import card.Card;

import org.json.JSONException;

public class Move {
	public static final byte[] MAGIC = { 1, 3, 3, 7 };

	public static final byte DRY = 1 << 5;
	public static final byte UPDATE = 2;
	public static final byte PLACE_CARD = 3;
	public static final byte TRASH_CARD = 4;
	public static final byte HINT = 5;
	public static final byte META_FIRST_META = DRY << 1;
	public static final byte META_YOURTURN = META_FIRST_META + 0;
	public static final byte META_READY = META_FIRST_META + 1;
	public static final byte META_UNREADY = META_FIRST_META + 2;
	public static final byte META_INVALID = META_FIRST_META + 3; //FIXME first, fix all other errors (META_MOVE_INVALID)
	public static final byte META_VALID = META_FIRST_META + 4; //FIXME first, fix all other errors (META_MOVE_VALID)
	public static final byte META_WON = META_FIRST_META + 5;
	public static final byte META_LOST = META_FIRST_META + 6;
	public static final byte META_LEAVE = META_FIRST_META + 7;
	public static final byte META_CONNECTION_VALID = META_FIRST_META + 8;
	public static final byte META_CONNECTION_INVALID = META_FIRST_META + 9;

	public static final byte HINT_COLOR = 0;
	public static final byte HINT_VALUE = 1;

	private byte moveType;
	private JSONObject jo;

	public Move(byte mT) {
		jo = new JSONObject();
		setMoveType(mT);
	}
	public Move(JSONObject jo) throws JSONException {
		//this.jo = (JSONObject)jo.clone();
		this.jo = jo; // TODO: clone?
//		moveType = (byte)jo.getInt("msgType");
	}
	public static Move newMove(Card c) {
		try {
			return new Move(c.toJson());
		} catch(JSONException ex) {
			throw new InternalHanabiError(ex);
		}
	}

	public JSONObject getJson() {
		return jo;
	}
	public String toJsonString() {
		if(jo == null) return "";
		return jo.toString();
	}
	public byte getMoveType() {
		return moveType; 
	}

	public int getOrigin() {
		try {
			return jo.getInt("origin");
		} catch(JSONException ex) {
			throw new InternalHanabiError(ex);
		}
	}

	public int getHintType() {
		if(moveType != HINT) {
			throw new RuntimeException("Internal Error: Hint type of non-hint move requested.");
		}
		try {
			return jo.getInt("type");
		} catch(JSONException ex) {
			throw new InternalHanabiError(ex);
		}
	}
	public int getValue() {
		if(moveType != HINT) {
			throw new RuntimeException("Internal Error: Hint value of non-hint move requested.");
		}
		try {
			return jo.getInt("value");
		} catch(JSONException ex) {
			throw new InternalHanabiError(ex);
		}
	}
	public int getHintRecipient() {
		if(moveType != HINT) {
			throw new RuntimeException("Internal Error: Target player ID of non-hint move requested.");
		}
		try {
			return jo.getInt("playerId");
		} catch(JSONException ex) {
			throw new InternalHanabiError(ex);
		}
	}
	
	public int getOwnId() {
		if(moveType != META_CONNECTION_VALID) {
			throw new RuntimeException("Internal Error: ownId of non-connection valid move requested.");
		}
		try {
			return jo.getInt("id");
		} catch(JSONException ex) {
			throw new InternalHanabiError(ex);
		}
	}

	public static Move makeInvalidMoveAnswer(Move m) {
		return new Move(META_INVALID);
	}

	public static Move makeItsYourTurnMessage() {
		return new Move(META_YOURTURN);
	}

	public boolean isMeta() {
		return moveType >= META_FIRST_META;
	}
	public void setMoveType(byte msgType) {
		this.moveType = msgType;
		try {
			jo.put("msgType", msgType);
		} catch (JSONException ex) {
			throw new InternalHanabiError(ex);
		}
	}
}
