package electrosphere.net.parser.net.message;

import io.github.studiorailgun.CircularByteBuffer;
import electrosphere.net.parser.util.ByteStreamUtils;
public class PlayerMessage extends NetworkMessage {

    /**
     * The types of messages available in this category.
     */
    public enum PlayerMessageType {
        SET_ID,
        SETINITIALDISCRETEPOSITION,
    }

    /**
     * The type of this message in particular.
     */
    PlayerMessageType messageType;
    int playerID;
    int initialDiscretePositionX;
    int initialDiscretePositionY;
    int initialDiscretePositionZ;

    /**
     * Constructor
     * @param messageType The type of this message
     */
    private PlayerMessage(PlayerMessageType messageType){
        this.type = MessageType.PLAYER_MESSAGE;
        this.messageType = messageType;
    }

    /**
     * Constructor
     */
    protected PlayerMessage(){
        this.type = MessageType.PLAYER_MESSAGE;
    }

    public PlayerMessageType getMessageSubtype(){
        return this.messageType;
    }

    /**
     * Gets playerID
     */
    public int getplayerID() {
        return playerID;
    }

    /**
     * Sets playerID
     */
    public void setplayerID(int playerID) {
        this.playerID = playerID;
    }

    /**
     * Gets initialDiscretePositionX
     */
    public int getinitialDiscretePositionX() {
        return initialDiscretePositionX;
    }

    /**
     * Sets initialDiscretePositionX
     */
    public void setinitialDiscretePositionX(int initialDiscretePositionX) {
        this.initialDiscretePositionX = initialDiscretePositionX;
    }

    /**
     * Gets initialDiscretePositionY
     */
    public int getinitialDiscretePositionY() {
        return initialDiscretePositionY;
    }

    /**
     * Sets initialDiscretePositionY
     */
    public void setinitialDiscretePositionY(int initialDiscretePositionY) {
        this.initialDiscretePositionY = initialDiscretePositionY;
    }

    /**
     * Gets initialDiscretePositionZ
     */
    public int getinitialDiscretePositionZ() {
        return initialDiscretePositionZ;
    }

    /**
     * Sets initialDiscretePositionZ
     */
    public void setinitialDiscretePositionZ(int initialDiscretePositionZ) {
        this.initialDiscretePositionZ = initialDiscretePositionZ;
    }

    /**
     * Removes the packet header from the buffer
     * @param byteBuffer The buffer
     */
    static void stripPacketHeader(CircularByteBuffer byteBuffer){
        byteBuffer.read(2);
    }

    /**
     * Checks if this message can be parsed (ie are all bytes present)
     * @param byteBuffer The buffer
     * @param secondByte The second byte, signifying the subtype of the message
     * @return true if the message can be parsed, false otherwise
     */
    public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
        switch(secondByte){
            case TypeBytes.PLAYER_MESSAGE_TYPE_SET_ID:
                if(byteBuffer.getRemaining() >= TypeBytes.PLAYER_MESSAGE_TYPE_SET_ID_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.PLAYER_MESSAGE_TYPE_SETINITIALDISCRETEPOSITION:
                if(byteBuffer.getRemaining() >= TypeBytes.PLAYER_MESSAGE_TYPE_SETINITIALDISCRETEPOSITION_SIZE){
                    return true;
                } else {
                    return false;
                }
        }
        return false;
    }

    /**
     * Parses a message of type Set_ID
     */
    public static PlayerMessage parseSet_IDMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        PlayerMessage rVal = (PlayerMessage)pool.get(MessageType.PLAYER_MESSAGE);
        rVal.messageType = PlayerMessageType.SET_ID;
        PlayerMessage.stripPacketHeader(byteBuffer);
        rVal.setplayerID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type Set_ID
     */
    public static PlayerMessage constructSet_IDMessage(int playerID){
        PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SET_ID);
        rVal.setplayerID(playerID);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type SetInitialDiscretePosition
     */
    public static PlayerMessage parseSetInitialDiscretePositionMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        PlayerMessage rVal = (PlayerMessage)pool.get(MessageType.PLAYER_MESSAGE);
        rVal.messageType = PlayerMessageType.SETINITIALDISCRETEPOSITION;
        PlayerMessage.stripPacketHeader(byteBuffer);
        rVal.setinitialDiscretePositionX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setinitialDiscretePositionY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setinitialDiscretePositionZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type SetInitialDiscretePosition
     */
    public static PlayerMessage constructSetInitialDiscretePositionMessage(int initialDiscretePositionX,int initialDiscretePositionY,int initialDiscretePositionZ){
        PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SETINITIALDISCRETEPOSITION);
        rVal.setinitialDiscretePositionX(initialDiscretePositionX);
        rVal.setinitialDiscretePositionY(initialDiscretePositionY);
        rVal.setinitialDiscretePositionZ(initialDiscretePositionZ);
        rVal.serialize();
        return rVal;
    }

    @Override
    void serialize(){
        byte[] intValues = new byte[8];
        switch(this.messageType){
            case SET_ID:
                rawBytes = new byte[2+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_PLAYER;
                //entity messaage header
                rawBytes[1] = TypeBytes.PLAYER_MESSAGE_TYPE_SET_ID;
                intValues = ByteStreamUtils.serializeIntToBytes(playerID);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                break;
            case SETINITIALDISCRETEPOSITION:
                rawBytes = new byte[2+4+4+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_PLAYER;
                //entity messaage header
                rawBytes[1] = TypeBytes.PLAYER_MESSAGE_TYPE_SETINITIALDISCRETEPOSITION;
                intValues = ByteStreamUtils.serializeIntToBytes(initialDiscretePositionX);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(initialDiscretePositionY);
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(initialDiscretePositionZ);
                for(int i = 0; i < 4; i++){
                    rawBytes[10+i] = intValues[i];
                }
                break;
        }
        serialized = true;
    }

}
