package electrosphere.net.parser.net.message;

import io.github.studiorailgun.CircularByteBuffer;
import electrosphere.net.parser.util.ByteStreamUtils;
import java.util.LinkedList;
import java.util.List;

public class InventoryMessage extends NetworkMessage {

    /**
     * The types of messages available in this category.
     */
    public enum InventoryMessageType {
        ADDITEMTOINVENTORY,
        REMOVEITEMFROMINVENTORY,
        CLIENTREQUESTEQUIPITEM,
        SERVERCOMMANDMOVEITEMCONTAINER,
        SERVERCOMMANDEQUIPITEM,
        SERVERCOMMANDUNEQUIPITEM,
        CLIENTREQUESTUNEQUIPITEM,
        CLIENTREQUESTADDTOOLBAR,
        CLIENTREQUESTADDNATURAL,
        CLIENTUPDATETOOLBAR,
        CLIENTREQUESTPERFORMITEMACTION,
        CLIENTREQUESTCRAFT,
    }

    /**
     * The type of this message in particular.
     */
    InventoryMessageType messageType;
    String itemTemplate;
    String equipPointId;
    int entityId;
    int equipperId;
    int containerType;
    int toolbarId;
    int itemActionCode;
    int itemActionCodeState;
    double viewTargetX;
    double viewTargetY;
    double viewTargetZ;
    int stationId;
    int recipeId;

    /**
     * Constructor
     * @param messageType The type of this message
     */
    private InventoryMessage(InventoryMessageType messageType){
        this.type = MessageType.INVENTORY_MESSAGE;
        this.messageType = messageType;
    }

    /**
     * Constructor
     */
    protected InventoryMessage(){
        this.type = MessageType.INVENTORY_MESSAGE;
    }

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

    /**
     * Gets itemTemplate
     */
    public String getitemTemplate() {
        return itemTemplate;
    }

    /**
     * Sets itemTemplate
     */
    public void setitemTemplate(String itemTemplate) {
        this.itemTemplate = itemTemplate;
    }

    /**
     * Gets equipPointId
     */
    public String getequipPointId() {
        return equipPointId;
    }

    /**
     * Sets equipPointId
     */
    public void setequipPointId(String equipPointId) {
        this.equipPointId = equipPointId;
    }

    /**
     * Gets entityId
     */
    public int getentityId() {
        return entityId;
    }

    /**
     * Sets entityId
     */
    public void setentityId(int entityId) {
        this.entityId = entityId;
    }

    /**
     * Gets equipperId
     */
    public int getequipperId() {
        return equipperId;
    }

    /**
     * Sets equipperId
     */
    public void setequipperId(int equipperId) {
        this.equipperId = equipperId;
    }

    /**
     * Gets containerType
     */
    public int getcontainerType() {
        return containerType;
    }

    /**
     * Sets containerType
     */
    public void setcontainerType(int containerType) {
        this.containerType = containerType;
    }

    /**
     * Gets toolbarId
     */
    public int gettoolbarId() {
        return toolbarId;
    }

    /**
     * Sets toolbarId
     */
    public void settoolbarId(int toolbarId) {
        this.toolbarId = toolbarId;
    }

    /**
     * Gets itemActionCode
     */
    public int getitemActionCode() {
        return itemActionCode;
    }

    /**
     * Sets itemActionCode
     */
    public void setitemActionCode(int itemActionCode) {
        this.itemActionCode = itemActionCode;
    }

    /**
     * Gets itemActionCodeState
     */
    public int getitemActionCodeState() {
        return itemActionCodeState;
    }

    /**
     * Sets itemActionCodeState
     */
    public void setitemActionCodeState(int itemActionCodeState) {
        this.itemActionCodeState = itemActionCodeState;
    }

    /**
     * Gets viewTargetX
     */
    public double getviewTargetX() {
        return viewTargetX;
    }

    /**
     * Sets viewTargetX
     */
    public void setviewTargetX(double viewTargetX) {
        this.viewTargetX = viewTargetX;
    }

    /**
     * Gets viewTargetY
     */
    public double getviewTargetY() {
        return viewTargetY;
    }

    /**
     * Sets viewTargetY
     */
    public void setviewTargetY(double viewTargetY) {
        this.viewTargetY = viewTargetY;
    }

    /**
     * Gets viewTargetZ
     */
    public double getviewTargetZ() {
        return viewTargetZ;
    }

    /**
     * Sets viewTargetZ
     */
    public void setviewTargetZ(double viewTargetZ) {
        this.viewTargetZ = viewTargetZ;
    }

    /**
     * Gets stationId
     */
    public int getstationId() {
        return stationId;
    }

    /**
     * Sets stationId
     */
    public void setstationId(int stationId) {
        this.stationId = stationId;
    }

    /**
     * Gets recipeId
     */
    public int getrecipeId() {
        return recipeId;
    }

    /**
     * Sets recipeId
     */
    public void setrecipeId(int recipeId) {
        this.recipeId = recipeId;
    }

    /**
     * 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.INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY:
                return InventoryMessage.canParseaddItemToInventoryMessage(byteBuffer);
            case TypeBytes.INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY:
                if(byteBuffer.getRemaining() >= TypeBytes.INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTEQUIPITEM:
                return InventoryMessage.canParseclientRequestEquipItemMessage(byteBuffer);
            case TypeBytes.INVENTORY_MESSAGE_TYPE_SERVERCOMMANDMOVEITEMCONTAINER:
                return InventoryMessage.canParseserverCommandMoveItemContainerMessage(byteBuffer);
            case TypeBytes.INVENTORY_MESSAGE_TYPE_SERVERCOMMANDEQUIPITEM:
                return InventoryMessage.canParseserverCommandEquipItemMessage(byteBuffer);
            case TypeBytes.INVENTORY_MESSAGE_TYPE_SERVERCOMMANDUNEQUIPITEM:
                return InventoryMessage.canParseserverCommandUnequipItemMessage(byteBuffer);
            case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTUNEQUIPITEM:
                return InventoryMessage.canParseclientRequestUnequipItemMessage(byteBuffer);
            case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR:
                if(byteBuffer.getRemaining() >= TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDNATURAL:
                if(byteBuffer.getRemaining() >= TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDNATURAL_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTUPDATETOOLBAR:
                if(byteBuffer.getRemaining() >= TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTUPDATETOOLBAR_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTPERFORMITEMACTION:
                return InventoryMessage.canParseclientRequestPerformItemActionMessage(byteBuffer);
            case TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTCRAFT:
                if(byteBuffer.getRemaining() >= TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTCRAFT_SIZE){
                    return true;
                } else {
                    return false;
                }
        }
        return false;
    }

    /**
     * Checks if a message of type addItemToInventory can be parsed from the byte stream
     */
    public static boolean canParseaddItemToInventoryMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        if(currentStreamLength < 6){
            return false;
        }
        int itemTemplateSize = 0;
        if(currentStreamLength < 10){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(6 + 0));
            temporaryByteQueue.add(byteBuffer.peek(6 + 1));
            temporaryByteQueue.add(byteBuffer.peek(6 + 2));
            temporaryByteQueue.add(byteBuffer.peek(6 + 3));
            itemTemplateSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 10 + itemTemplateSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type addItemToInventory
     */
    public static InventoryMessage parseaddItemToInventoryMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.ADDITEMTOINVENTORY;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setitemTemplate(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type addItemToInventory
     */
    public static InventoryMessage constructaddItemToInventoryMessage(int entityId,String itemTemplate){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.ADDITEMTOINVENTORY);
        rVal.setentityId(entityId);
        rVal.setitemTemplate(itemTemplate);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type removeItemFromInventory
     */
    public static InventoryMessage parseremoveItemFromInventoryMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.REMOVEITEMFROMINVENTORY;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type removeItemFromInventory
     */
    public static InventoryMessage constructremoveItemFromInventoryMessage(int entityId){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.REMOVEITEMFROMINVENTORY);
        rVal.setentityId(entityId);
        rVal.serialize();
        return rVal;
    }

    /**
     * Checks if a message of type clientRequestEquipItem can be parsed from the byte stream
     */
    public static boolean canParseclientRequestEquipItemMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        int equipPointIdSize = 0;
        if(currentStreamLength < 6){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(2 + 0));
            temporaryByteQueue.add(byteBuffer.peek(2 + 1));
            temporaryByteQueue.add(byteBuffer.peek(2 + 2));
            temporaryByteQueue.add(byteBuffer.peek(2 + 3));
            equipPointIdSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 6 + equipPointIdSize){
            return false;
        }
        if(currentStreamLength < 10 + equipPointIdSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type clientRequestEquipItem
     */
    public static InventoryMessage parseclientRequestEquipItemMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.CLIENTREQUESTEQUIPITEM;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setequipPointId(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type clientRequestEquipItem
     */
    public static InventoryMessage constructclientRequestEquipItemMessage(String equipPointId,int entityId){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTEQUIPITEM);
        rVal.setequipPointId(equipPointId);
        rVal.setentityId(entityId);
        rVal.serialize();
        return rVal;
    }

    /**
     * Checks if a message of type serverCommandMoveItemContainer can be parsed from the byte stream
     */
    public static boolean canParseserverCommandMoveItemContainerMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        if(currentStreamLength < 6){
            return false;
        }
        if(currentStreamLength < 10){
            return false;
        }
        int equipPointIdSize = 0;
        if(currentStreamLength < 14){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(10 + 0));
            temporaryByteQueue.add(byteBuffer.peek(10 + 1));
            temporaryByteQueue.add(byteBuffer.peek(10 + 2));
            temporaryByteQueue.add(byteBuffer.peek(10 + 3));
            equipPointIdSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 14 + equipPointIdSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type serverCommandMoveItemContainer
     */
    public static InventoryMessage parseserverCommandMoveItemContainerMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.SERVERCOMMANDMOVEITEMCONTAINER;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setcontainerType(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setequipPointId(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type serverCommandMoveItemContainer
     */
    public static InventoryMessage constructserverCommandMoveItemContainerMessage(int entityId,int containerType,String equipPointId){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDMOVEITEMCONTAINER);
        rVal.setentityId(entityId);
        rVal.setcontainerType(containerType);
        rVal.setequipPointId(equipPointId);
        rVal.serialize();
        return rVal;
    }

    /**
     * Checks if a message of type serverCommandEquipItem can be parsed from the byte stream
     */
    public static boolean canParseserverCommandEquipItemMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        if(currentStreamLength < 6){
            return false;
        }
        if(currentStreamLength < 10){
            return false;
        }
        int equipPointIdSize = 0;
        if(currentStreamLength < 14){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(10 + 0));
            temporaryByteQueue.add(byteBuffer.peek(10 + 1));
            temporaryByteQueue.add(byteBuffer.peek(10 + 2));
            temporaryByteQueue.add(byteBuffer.peek(10 + 3));
            equipPointIdSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 14 + equipPointIdSize){
            return false;
        }
        if(currentStreamLength < 18 + equipPointIdSize){
            return false;
        }
        int itemTemplateSize = 0;
        if(currentStreamLength < 22){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(18 + equipPointIdSize + 0));
            temporaryByteQueue.add(byteBuffer.peek(18 + equipPointIdSize + 1));
            temporaryByteQueue.add(byteBuffer.peek(18 + equipPointIdSize + 2));
            temporaryByteQueue.add(byteBuffer.peek(18 + equipPointIdSize + 3));
            itemTemplateSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 22 + equipPointIdSize + itemTemplateSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type serverCommandEquipItem
     */
    public static InventoryMessage parseserverCommandEquipItemMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.SERVERCOMMANDEQUIPITEM;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setequipperId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setcontainerType(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setequipPointId(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setitemTemplate(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type serverCommandEquipItem
     */
    public static InventoryMessage constructserverCommandEquipItemMessage(int equipperId,int containerType,String equipPointId,int entityId,String itemTemplate){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDEQUIPITEM);
        rVal.setequipperId(equipperId);
        rVal.setcontainerType(containerType);
        rVal.setequipPointId(equipPointId);
        rVal.setentityId(entityId);
        rVal.setitemTemplate(itemTemplate);
        rVal.serialize();
        return rVal;
    }

    /**
     * Checks if a message of type serverCommandUnequipItem can be parsed from the byte stream
     */
    public static boolean canParseserverCommandUnequipItemMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        if(currentStreamLength < 6){
            return false;
        }
        if(currentStreamLength < 10){
            return false;
        }
        int equipPointIdSize = 0;
        if(currentStreamLength < 14){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(10 + 0));
            temporaryByteQueue.add(byteBuffer.peek(10 + 1));
            temporaryByteQueue.add(byteBuffer.peek(10 + 2));
            temporaryByteQueue.add(byteBuffer.peek(10 + 3));
            equipPointIdSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 14 + equipPointIdSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type serverCommandUnequipItem
     */
    public static InventoryMessage parseserverCommandUnequipItemMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.SERVERCOMMANDUNEQUIPITEM;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setequipperId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setcontainerType(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setequipPointId(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type serverCommandUnequipItem
     */
    public static InventoryMessage constructserverCommandUnequipItemMessage(int equipperId,int containerType,String equipPointId){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.SERVERCOMMANDUNEQUIPITEM);
        rVal.setequipperId(equipperId);
        rVal.setcontainerType(containerType);
        rVal.setequipPointId(equipPointId);
        rVal.serialize();
        return rVal;
    }

    /**
     * Checks if a message of type clientRequestUnequipItem can be parsed from the byte stream
     */
    public static boolean canParseclientRequestUnequipItemMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        int equipPointIdSize = 0;
        if(currentStreamLength < 6){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(2 + 0));
            temporaryByteQueue.add(byteBuffer.peek(2 + 1));
            temporaryByteQueue.add(byteBuffer.peek(2 + 2));
            temporaryByteQueue.add(byteBuffer.peek(2 + 3));
            equipPointIdSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 6 + equipPointIdSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type clientRequestUnequipItem
     */
    public static InventoryMessage parseclientRequestUnequipItemMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.CLIENTREQUESTUNEQUIPITEM;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setequipPointId(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type clientRequestUnequipItem
     */
    public static InventoryMessage constructclientRequestUnequipItemMessage(String equipPointId){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTUNEQUIPITEM);
        rVal.setequipPointId(equipPointId);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type clientRequestAddToolbar
     */
    public static InventoryMessage parseclientRequestAddToolbarMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.CLIENTREQUESTADDTOOLBAR;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.settoolbarId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type clientRequestAddToolbar
     */
    public static InventoryMessage constructclientRequestAddToolbarMessage(int entityId,int toolbarId){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDTOOLBAR);
        rVal.setentityId(entityId);
        rVal.settoolbarId(toolbarId);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type clientRequestAddNatural
     */
    public static InventoryMessage parseclientRequestAddNaturalMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.CLIENTREQUESTADDNATURAL;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type clientRequestAddNatural
     */
    public static InventoryMessage constructclientRequestAddNaturalMessage(int entityId){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTADDNATURAL);
        rVal.setentityId(entityId);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type clientUpdateToolbar
     */
    public static InventoryMessage parseclientUpdateToolbarMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.CLIENTUPDATETOOLBAR;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.settoolbarId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type clientUpdateToolbar
     */
    public static InventoryMessage constructclientUpdateToolbarMessage(int toolbarId){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTUPDATETOOLBAR);
        rVal.settoolbarId(toolbarId);
        rVal.serialize();
        return rVal;
    }

    /**
     * Checks if a message of type clientRequestPerformItemAction can be parsed from the byte stream
     */
    public static boolean canParseclientRequestPerformItemActionMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        int equipPointIdSize = 0;
        if(currentStreamLength < 6){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(2 + 0));
            temporaryByteQueue.add(byteBuffer.peek(2 + 1));
            temporaryByteQueue.add(byteBuffer.peek(2 + 2));
            temporaryByteQueue.add(byteBuffer.peek(2 + 3));
            equipPointIdSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 6 + equipPointIdSize){
            return false;
        }
        if(currentStreamLength < 10 + equipPointIdSize){
            return false;
        }
        if(currentStreamLength < 14 + equipPointIdSize){
            return false;
        }
        if(currentStreamLength < 22 + equipPointIdSize){
            return false;
        }
        if(currentStreamLength < 30 + equipPointIdSize){
            return false;
        }
        if(currentStreamLength < 38 + equipPointIdSize){
            return false;
        }
        return true;
    }

    /**
     * Parses a message of type clientRequestPerformItemAction
     */
    public static InventoryMessage parseclientRequestPerformItemActionMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.CLIENTREQUESTPERFORMITEMACTION;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setequipPointId(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        rVal.setitemActionCode(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setitemActionCodeState(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setviewTargetX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setviewTargetY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        rVal.setviewTargetZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type clientRequestPerformItemAction
     */
    public static InventoryMessage constructclientRequestPerformItemActionMessage(String equipPointId,int itemActionCode,int itemActionCodeState,double viewTargetX,double viewTargetY,double viewTargetZ){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTPERFORMITEMACTION);
        rVal.setequipPointId(equipPointId);
        rVal.setitemActionCode(itemActionCode);
        rVal.setitemActionCodeState(itemActionCodeState);
        rVal.setviewTargetX(viewTargetX);
        rVal.setviewTargetY(viewTargetY);
        rVal.setviewTargetZ(viewTargetZ);
        rVal.serialize();
        return rVal;
    }

    /**
     * Parses a message of type clientRequestCraft
     */
    public static InventoryMessage parseclientRequestCraftMessage(CircularByteBuffer byteBuffer, MessagePool pool){
        InventoryMessage rVal = (InventoryMessage)pool.get(MessageType.INVENTORY_MESSAGE);
        rVal.messageType = InventoryMessageType.CLIENTREQUESTCRAFT;
        InventoryMessage.stripPacketHeader(byteBuffer);
        rVal.setentityId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setstationId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        rVal.setrecipeId(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
        return rVal;
    }

    /**
     * Constructs a message of type clientRequestCraft
     */
    public static InventoryMessage constructclientRequestCraftMessage(int entityId,int stationId,int recipeId){
        InventoryMessage rVal = new InventoryMessage(InventoryMessageType.CLIENTREQUESTCRAFT);
        rVal.setentityId(entityId);
        rVal.setstationId(stationId);
        rVal.setrecipeId(recipeId);
        rVal.serialize();
        return rVal;
    }

    @Override
    void serialize(){
        byte[] intValues = new byte[8];
        byte[] stringBytes;
        switch(this.messageType){
            case ADDITEMTOINVENTORY:
                rawBytes = new byte[2+4+4+itemTemplate.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_ADDITEMTOINVENTORY;
                intValues = ByteStreamUtils.serializeIntToBytes(entityId);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(itemTemplate.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                stringBytes = itemTemplate.getBytes();
                for(int i = 0; i < itemTemplate.length(); i++){
                    rawBytes[10+i] = stringBytes[i];
                }
                break;
            case REMOVEITEMFROMINVENTORY:
                rawBytes = new byte[2+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_REMOVEITEMFROMINVENTORY;
                intValues = ByteStreamUtils.serializeIntToBytes(entityId);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                break;
            case CLIENTREQUESTEQUIPITEM:
                rawBytes = new byte[2+4+equipPointId.length()+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTEQUIPITEM;
                intValues = ByteStreamUtils.serializeIntToBytes(equipPointId.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                stringBytes = equipPointId.getBytes();
                for(int i = 0; i < equipPointId.length(); i++){
                    rawBytes[6+i] = stringBytes[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(entityId);
                for(int i = 0; i < 4; i++){
                    rawBytes[6+equipPointId.length()+i] = intValues[i];
                }
                break;
            case SERVERCOMMANDMOVEITEMCONTAINER:
                rawBytes = new byte[2+4+4+4+equipPointId.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_SERVERCOMMANDMOVEITEMCONTAINER;
                intValues = ByteStreamUtils.serializeIntToBytes(entityId);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(containerType);
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(equipPointId.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[10+i] = intValues[i];
                }
                stringBytes = equipPointId.getBytes();
                for(int i = 0; i < equipPointId.length(); i++){
                    rawBytes[14+i] = stringBytes[i];
                }
                break;
            case SERVERCOMMANDEQUIPITEM:
                rawBytes = new byte[2+4+4+4+equipPointId.length()+4+4+itemTemplate.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_SERVERCOMMANDEQUIPITEM;
                intValues = ByteStreamUtils.serializeIntToBytes(equipperId);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(containerType);
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(equipPointId.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[10+i] = intValues[i];
                }
                stringBytes = equipPointId.getBytes();
                for(int i = 0; i < equipPointId.length(); i++){
                    rawBytes[14+i] = stringBytes[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(entityId);
                for(int i = 0; i < 4; i++){
                    rawBytes[14+equipPointId.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(itemTemplate.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[18+equipPointId.length()+i] = intValues[i];
                }
                stringBytes = itemTemplate.getBytes();
                for(int i = 0; i < itemTemplate.length(); i++){
                    rawBytes[22+equipPointId.length()+i] = stringBytes[i];
                }
                break;
            case SERVERCOMMANDUNEQUIPITEM:
                rawBytes = new byte[2+4+4+4+equipPointId.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_SERVERCOMMANDUNEQUIPITEM;
                intValues = ByteStreamUtils.serializeIntToBytes(equipperId);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(containerType);
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(equipPointId.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[10+i] = intValues[i];
                }
                stringBytes = equipPointId.getBytes();
                for(int i = 0; i < equipPointId.length(); i++){
                    rawBytes[14+i] = stringBytes[i];
                }
                break;
            case CLIENTREQUESTUNEQUIPITEM:
                rawBytes = new byte[2+4+equipPointId.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTUNEQUIPITEM;
                intValues = ByteStreamUtils.serializeIntToBytes(equipPointId.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                stringBytes = equipPointId.getBytes();
                for(int i = 0; i < equipPointId.length(); i++){
                    rawBytes[6+i] = stringBytes[i];
                }
                break;
            case CLIENTREQUESTADDTOOLBAR:
                rawBytes = new byte[2+4+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDTOOLBAR;
                intValues = ByteStreamUtils.serializeIntToBytes(entityId);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(toolbarId);
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                break;
            case CLIENTREQUESTADDNATURAL:
                rawBytes = new byte[2+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTADDNATURAL;
                intValues = ByteStreamUtils.serializeIntToBytes(entityId);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                break;
            case CLIENTUPDATETOOLBAR:
                rawBytes = new byte[2+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTUPDATETOOLBAR;
                intValues = ByteStreamUtils.serializeIntToBytes(toolbarId);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                break;
            case CLIENTREQUESTPERFORMITEMACTION:
                rawBytes = new byte[2+4+equipPointId.length()+4+4+8+8+8];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTPERFORMITEMACTION;
                intValues = ByteStreamUtils.serializeIntToBytes(equipPointId.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                stringBytes = equipPointId.getBytes();
                for(int i = 0; i < equipPointId.length(); i++){
                    rawBytes[6+i] = stringBytes[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(itemActionCode);
                for(int i = 0; i < 4; i++){
                    rawBytes[6+equipPointId.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(itemActionCodeState);
                for(int i = 0; i < 4; i++){
                    rawBytes[10+equipPointId.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(viewTargetX);
                for(int i = 0; i < 8; i++){
                    rawBytes[14+equipPointId.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(viewTargetY);
                for(int i = 0; i < 8; i++){
                    rawBytes[22+equipPointId.length()+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeDoubleToBytes(viewTargetZ);
                for(int i = 0; i < 8; i++){
                    rawBytes[30+equipPointId.length()+i] = intValues[i];
                }
                break;
            case CLIENTREQUESTCRAFT:
                rawBytes = new byte[2+4+4+4];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_INVENTORY;
                //entity messaage header
                rawBytes[1] = TypeBytes.INVENTORY_MESSAGE_TYPE_CLIENTREQUESTCRAFT;
                intValues = ByteStreamUtils.serializeIntToBytes(entityId);
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(stationId);
                for(int i = 0; i < 4; i++){
                    rawBytes[6+i] = intValues[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(recipeId);
                for(int i = 0; i < 4; i++){
                    rawBytes[10+i] = intValues[i];
                }
                break;
        }
        serialized = true;
    }

}
