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 AuthMessage extends NetworkMessage {

    public enum AuthMessageType {
        AUTHREQUEST,
        AUTHDETAILS,
        AUTHSUCCESS,
        AUTHFAILURE,
    }

    AuthMessageType messageType;
    String user;
    String pass;

    AuthMessage(AuthMessageType messageType){
        this.type = MessageType.AUTH_MESSAGE;
        this.messageType = messageType;
    }

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

    public String getuser() {
        return user;
    }

    public void setuser(String user) {
        this.user = user;
    }

    public String getpass() {
        return pass;
    }

    public void setpass(String pass) {
        this.pass = pass;
    }

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

    public static boolean canParseMessage(CircularByteBuffer byteBuffer, byte secondByte){
        switch(secondByte){
            case TypeBytes.AUTH_MESSAGE_TYPE_AUTHREQUEST:
                if(byteBuffer.getRemaining() >= TypeBytes.AUTH_MESSAGE_TYPE_AUTHREQUEST_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.AUTH_MESSAGE_TYPE_AUTHDETAILS:
                return AuthMessage.canParseAuthDetailsMessage(byteBuffer);
            case TypeBytes.AUTH_MESSAGE_TYPE_AUTHSUCCESS:
                if(byteBuffer.getRemaining() >= TypeBytes.AUTH_MESSAGE_TYPE_AUTHSUCCESS_SIZE){
                    return true;
                } else {
                    return false;
                }
            case TypeBytes.AUTH_MESSAGE_TYPE_AUTHFAILURE:
                if(byteBuffer.getRemaining() >= TypeBytes.AUTH_MESSAGE_TYPE_AUTHFAILURE_SIZE){
                    return true;
                } else {
                    return false;
                }
        }
        return false;
    }

    public static AuthMessage parseAuthRequestMessage(CircularByteBuffer byteBuffer){
        AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHREQUEST);
        stripPacketHeader(byteBuffer);
        return rVal;
    }

    public static AuthMessage constructAuthRequestMessage(){
        AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHREQUEST);
        rVal.serialize();
        return rVal;
    }

    public static boolean canParseAuthDetailsMessage(CircularByteBuffer byteBuffer){
        int currentStreamLength = byteBuffer.getRemaining();
        List<Byte> temporaryByteQueue = new LinkedList<Byte>();
        int userSize = 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));
            userSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 6 + userSize){
            return false;
        }
        int passSize = 0;
        if(currentStreamLength < 10){
            return false;
        } else {
            temporaryByteQueue.add(byteBuffer.peek(6 + userSize + 0));
            temporaryByteQueue.add(byteBuffer.peek(6 + userSize + 1));
            temporaryByteQueue.add(byteBuffer.peek(6 + userSize + 2));
            temporaryByteQueue.add(byteBuffer.peek(6 + userSize + 3));
            passSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
        }
        if(currentStreamLength < 10 + userSize + passSize){
            return false;
        }
        return true;
    }

    public static AuthMessage parseAuthDetailsMessage(CircularByteBuffer byteBuffer){
        AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHDETAILS);
        stripPacketHeader(byteBuffer);
        rVal.setuser(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        rVal.setpass(ByteStreamUtils.popStringFromByteQueue(byteBuffer));
        return rVal;
    }

    public static AuthMessage constructAuthDetailsMessage(String user,String pass){
        AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHDETAILS);
        rVal.setuser(user);
        rVal.setpass(pass);
        rVal.serialize();
        return rVal;
    }

    public static AuthMessage parseAuthSuccessMessage(CircularByteBuffer byteBuffer){
        AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHSUCCESS);
        stripPacketHeader(byteBuffer);
        return rVal;
    }

    public static AuthMessage constructAuthSuccessMessage(){
        AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHSUCCESS);
        rVal.serialize();
        return rVal;
    }

    public static AuthMessage parseAuthFailureMessage(CircularByteBuffer byteBuffer){
        AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHFAILURE);
        stripPacketHeader(byteBuffer);
        return rVal;
    }

    public static AuthMessage constructAuthFailureMessage(){
        AuthMessage rVal = new AuthMessage(AuthMessageType.AUTHFAILURE);
        rVal.serialize();
        return rVal;
    }

    @Override
    void serialize(){
        byte[] intValues = new byte[8];
        byte[] stringBytes;
        switch(this.messageType){
            case AUTHREQUEST:
                rawBytes = new byte[2];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_AUTH;
                //entity messaage header
                rawBytes[1] = TypeBytes.AUTH_MESSAGE_TYPE_AUTHREQUEST;
                break;
            case AUTHDETAILS:
                rawBytes = new byte[2+4+user.length()+4+pass.length()];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_AUTH;
                //entity messaage header
                rawBytes[1] = TypeBytes.AUTH_MESSAGE_TYPE_AUTHDETAILS;
                intValues = ByteStreamUtils.serializeIntToBytes(user.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[2+i] = intValues[i];
                }
                stringBytes = user.getBytes();
                for(int i = 0; i < user.length(); i++){
                    rawBytes[6+i] = stringBytes[i];
                }
                intValues = ByteStreamUtils.serializeIntToBytes(pass.length());
                for(int i = 0; i < 4; i++){
                    rawBytes[6+user.length()+i] = intValues[i];
                }
                stringBytes = pass.getBytes();
                for(int i = 0; i < pass.length(); i++){
                    rawBytes[10+user.length()+i] = stringBytes[i];
                }
                break;
            case AUTHSUCCESS:
                rawBytes = new byte[2];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_AUTH;
                //entity messaage header
                rawBytes[1] = TypeBytes.AUTH_MESSAGE_TYPE_AUTHSUCCESS;
                break;
            case AUTHFAILURE:
                rawBytes = new byte[2];
                //message header
                rawBytes[0] = TypeBytes.MESSAGE_TYPE_AUTH;
                //entity messaage header
                rawBytes[1] = TypeBytes.AUTH_MESSAGE_TYPE_AUTHFAILURE;
                break;
        }
        serialized = true;
    }

}
