package electrosphere.net.parser.net.message;

import electrosphere.net.parser.util.ByteStreamUtils;
import electrosphere.net.parser.net.raw.CircularByteBuffer;
import java.util.LinkedList;
import java.util.List;

public class CharacterMessage extends NetworkMessage {

    public enum CharacterMessageType {
        REQUESTCHARACTERLIST,
        RESPONSECHARACTERLIST,
        REQUESTCREATECHARACTER,
        RESPONSECREATECHARACTERSUCCESS,
        RESPONSECREATECHARACTERFAILURE,
        REQUESTSPAWNCHARACTER,
        RESPONSESPAWNCHARACTER,
    }

    CharacterMessageType messageType;
    String data;

    CharacterMessage(CharacterMessageType messageType){
        this.type = MessageType.CHARACTER_MESSAGE;
        this.messageType = messageType;
    }

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

    public String getdata() {
        return data;
    }

    public void setdata(String data) {
        this.data = data;
    }

    static void stripPacketHeader(CircularByteBuffer byteBuffer){
        byteBuffer.read(2);
    }

    public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
        switch(secondByte){
            case TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST:
                if(byteBuffer.getRemaining() >= TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSECHARACTERLIST:
                return CharacterMessage.canParseResponseCharacterListMessage(byteBuffer);
            case TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTCREATECHARACTER:
                return CharacterMessage.canParseRequestCreateCharacterMessage(byteBuffer);
            case TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERSUCCESS:
                if(byteBuffer.getRemaining() >= TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERSUCCESS_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE:
                if(byteBuffer.getRemaining() >= TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER:
                if(byteBuffer.getRemaining() >= TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSESPAWNCHARACTER:
                return CharacterMessage.canParseResponseSpawnCharacterMessage(byteBuffer);
        }
        return false;
    }

    public static CharacterMessage parseRequestCharacterListMessage(CircularByteBuffer byteBuffer){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCHARACTERLIST);
        stripPacketHeader(byteBuffer);
        return rVal;
    }

    public static CharacterMessage constructRequestCharacterListMessage(){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCHARACTERLIST);
        rVal.serialize();
        return rVal;
    }

    public static boolean canParseResponseCharacterListMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        int dataSize = 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));
            dataSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 6 + dataSize){
            return false;
        }
        return true;
    }

    public static CharacterMessage parseResponseCharacterListMessage(CircularByteBuffer byteBuffer){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECHARACTERLIST);
        stripPacketHeader(byteBuffer);
        rVal.setdata(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    public static CharacterMessage constructResponseCharacterListMessage(String data){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECHARACTERLIST);
        rVal.setdata(data);
        rVal.serialize();
        return rVal;
    }

    public static boolean canParseRequestCreateCharacterMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        int dataSize = 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));
            dataSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 6 + dataSize){
            return false;
        }
        return true;
    }

    public static CharacterMessage parseRequestCreateCharacterMessage(CircularByteBuffer byteBuffer){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCREATECHARACTER);
        stripPacketHeader(byteBuffer);
        rVal.setdata(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    public static CharacterMessage constructRequestCreateCharacterMessage(String data){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTCREATECHARACTER);
        rVal.setdata(data);
        rVal.serialize();
        return rVal;
    }

    public static CharacterMessage parseResponseCreateCharacterSuccessMessage(CircularByteBuffer byteBuffer){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERSUCCESS);
        stripPacketHeader(byteBuffer);
        return rVal;
    }

    public static CharacterMessage constructResponseCreateCharacterSuccessMessage(){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERSUCCESS);
        rVal.serialize();
        return rVal;
    }

    public static CharacterMessage parseResponseCreateCharacterFailureMessage(CircularByteBuffer byteBuffer){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERFAILURE);
        stripPacketHeader(byteBuffer);
        return rVal;
    }

    public static CharacterMessage constructResponseCreateCharacterFailureMessage(){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSECREATECHARACTERFAILURE);
        rVal.serialize();
        return rVal;
    }

    public static CharacterMessage parseRequestSpawnCharacterMessage(CircularByteBuffer byteBuffer){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTSPAWNCHARACTER);
        stripPacketHeader(byteBuffer);
        return rVal;
    }

    public static CharacterMessage constructRequestSpawnCharacterMessage(){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.REQUESTSPAWNCHARACTER);
        rVal.serialize();
        return rVal;
    }

    public static boolean canParseResponseSpawnCharacterMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        int dataSize = 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));
            dataSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 6 + dataSize){
            return false;
        }
        return true;
    }

    public static CharacterMessage parseResponseSpawnCharacterMessage(CircularByteBuffer byteBuffer){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSESPAWNCHARACTER);
        stripPacketHeader(byteBuffer);
        rVal.setdata(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    public static CharacterMessage constructResponseSpawnCharacterMessage(String data){
        CharacterMessage rVal = new CharacterMessage(CharacterMessageType.RESPONSESPAWNCHARACTER);
        rVal.setdata(data);
        rVal.serialize();
        return rVal;
    }

    @Override
    void serialize(){
        byte[] intValues = new byte[8];
        byte[] stringBytes;
        switch(this.messageType){
            case REQUESTCHARACTERLIST:
                rawBytes = new byte[2];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_CHARACTER;
                //entity messaage header
                rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTCHARACTERLIST;
                break;
            case RESPONSECHARACTERLIST:
                rawBytes = new byte[2+4+data.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_CHARACTER;
                //entity messaage header
                rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSECHARACTERLIST;
                intValues = ByteStreamUtils.serializeIntToBytes(data.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                stringBytes = data.getBytes();
                for(int i = 0; i < data.length(); i++){
                    rawBytes[6+i] = stringBytes[i];
                }
                break;
            case REQUESTCREATECHARACTER:
                rawBytes = new byte[2+4+data.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_CHARACTER;
                //entity messaage header
                rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTCREATECHARACTER;
                intValues = ByteStreamUtils.serializeIntToBytes(data.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                stringBytes = data.getBytes();
                for(int i = 0; i < data.length(); i++){
                    rawBytes[6+i] = stringBytes[i];
                }
                break;
            case RESPONSECREATECHARACTERSUCCESS:
                rawBytes = new byte[2];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_CHARACTER;
                //entity messaage header
                rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERSUCCESS;
                break;
            case RESPONSECREATECHARACTERFAILURE:
                rawBytes = new byte[2];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_CHARACTER;
                //entity messaage header
                rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSECREATECHARACTERFAILURE;
                break;
            case REQUESTSPAWNCHARACTER:
                rawBytes = new byte[2];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_CHARACTER;
                //entity messaage header
                rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_REQUESTSPAWNCHARACTER;
                break;
            case RESPONSESPAWNCHARACTER:
                rawBytes = new byte[2+4+data.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_CHARACTER;
                //entity messaage header
                rawBytes[1] = TypeBytes.CHARACTER_MESSAGE_TYPE_RESPONSESPAWNCHARACTER;
                intValues = ByteStreamUtils.serializeIntToBytes(data.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                stringBytes = data.getBytes();
                for(int i = 0; i < data.length(); i++){
                    rawBytes[6+i] = stringBytes[i];
                }
                break;
        }
        serialized = true;
    }

}
