/*
 * Decompiled with CFR 0_101, deobfucsted by Skylinerw
 * 
 * Could not load the following classes:
 *  com.google.common.annotations.VisibleForTesting
 *  com.google.common.collect.Lists
 */
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import NBTByteArray;
import NBTByte;
import NBTCompound;
import NBTDouble;
import NBTFloat;
import NBTIntArray;
import NBTFloat;
import NBTList;
import NBTLong;
import NBTPrimitive;
import NBTShort;
import NBTString;
import NBTBase;
import NBTParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class stringToNBT {
    private static final Pattern regexDouble1 = Pattern.compile("[-+]?(?:[0-9]+[.]|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?", 2);
    private static final Pattern regexDouble2 = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", 2);
    private static final Pattern regexFloat = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?f", 2);
    private static final Pattern regexByte = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)b", 2);
    private static final Pattern regexLong = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)l", 2);
    private static final Pattern regexShort = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)s", 2);
    private static final Pattern regexInt = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)");
    private final String inputString;
    private int cursor;

    public static NBTCompound getNewInstance(String string) throws NBTParseException {
        return new stringToNBT(string).parse();
    }

    @VisibleForTesting
    NBTCompound parse() throws NBTParseException {
        NBTCompound nbtcompound = this.createCompoundNBT();
        this.movePastWhitespace();
        if (this.withinBounds()) {
            ++this.cursor;
            throw this.newParseException("Trailing data found");
        }
        return nbtcompound;
    }

    @VisibleForTesting
    stringToNBT(String raw) {
        this.inputString = raw;
    }

    protected String getKey() throws NBTParseException {
        this.movePastWhitespace();
        if (!this.withinBounds()) { // If at end of string, throw.
            throw this.newParseException("Expected key");
        }
        return this.getCurrentChar() == '\"' ? this.getQuotedString() : this.getUnquotedString();
    }

    private NBTParseException newParseException(String message) {
        return new NBTParseException(message, this.inputString, this.cursor);
    }

    protected NBTBase getSimpleValue() throws NBTParseException {
        this.movePastWhitespace();
        if (this.getCurrentChar() == '\"') {
            return new NBTString(this.getQuotedString());
        }
        String string = this.getUnquotedString();
        if (string.isEmpty()) {
            throw this.newParseException("Expected value");
        }
        return this.createSimpleNBT(string);
    }

    private NBTBase createSimpleNBT(String value) {
        try {
            if (regexFloat.matcher((CharSequence)value).matches()) {
                return new NBTFloat(Float.parseFloat(value.substring(0, value.length() - 1)));
            }
            if (regexByte.matcher((CharSequence)value).matches()) {
                return new NBTByte(Byte.parseByte(value.substring(0, value.length() - 1)));
            }
            if (regexLong.matcher((CharSequence)value).matches()) {
                return new NBTLong(Long.parseLong(value.substring(0, value.length() - 1)));
            }
            if (regexShort.matcher((CharSequence)value).matches()) {
                return new NBTShort(Short.parseShort(value.substring(0, value.length() - 1)));
            }
            if (regexInt.matcher((CharSequence)value).matches()) {
                return new NBTInteger(Integer.parseInt(value));
            }
            if (regexDouble2.matcher((CharSequence)value).matches()) {
                return new NBTDouble(Double.parseDouble(value.substring(0, value.length() - 1)));
            }
            if (regexDouble1.matcher((CharSequence)value).matches()) {
                return new NBTDouble(Double.parseDouble(value));
            }
            if ("true".equalsIgnoreCase(value)) {
                return new NBTByte(1);
            }
            if ("false".equalsIgnoreCase(value)) {
                return new NBTByte(0);
            }
        }
        catch (NumberFormatException exception) {
            // empty catch block
        }
        return new NBTString(value);
    }

    private String getQuotedString() throws NBTParseException {
        int cursorPos = ++this.cursor;
        StringBuilder stringBuilder = null;
        boolean escaping = false;
        while (this.withinBounds()) {
            char currentChar = this.getToNextChar();
            if (escaping) {
                if (currentChar != '\\' && currentChar != '\"') {
                    throw this.newParseException("Invalid escape of '" + currentChar + "'");
                }
                escaping = false;
            } else {
                if (currentChar == '\\') {
                    escaping = true;
                    if (stringBuilder != null) continue;
                    stringBuilder = new StringBuilder(this.inputString.substring(cursorPos, this.cursor - 1));
                    continue;
                }
                if (currentChar == '\"') {
                    return stringBuilder == null ? this.inputString.substring(cursorPos, this.cursor - 1) : stringBuilder.toString();
                }
            }
            if (stringBuilder == null) continue;
            stringBuilder.append(currentChar);
        }
        throw this.newParseException("Missing termination quote");
    }

    private String getUnquotedString() {
        int n = this.cursor;
        while (this.withinBounds() && this.isValidChar(this.getCurrentChar())) {
            ++this.cursor;
        }
        return this.inputString.substring(n, this.cursor);
    }

    protected NBTBase getValue() throws NBTParseException {
        this.movePastWhitespace();
        if (!this.withinBounds()) {
            throw this.newParseException("Expected value");
        }
        char currentChar = this.getCurrentChar();
        if (currentChar == '{') {
            return this.createCompoundNBT();
        }
        if (currentChar == '[') {
            return this.getArrayOrList();
        }
        return this.getSimpleValue();
    }

    protected NBTBase getArrayOrList() throws NBTParseException {
        char c;
        if (this.cursorPlusNWithinBounds(1) && ((c = this.getCharAtCursorPlusN(1)) == 'B' || c == 'I') && this.cursorPlusNWithinBounds(2) && this.getCharAtCursorPlusN(2) == ';') {
            return this.getArrayValue();
        }
        return this.createListNBT();
    }

    protected NBTCompound createCompoundNBT() throws NBTParseException {
        this.moveToNextChar('{');
        NBTCompound nbtcompound = new NBTCompound();
        this.movePastWhitespace();
        while (this.withinBounds() && this.getCurrentChar() != '}') {
            String key = this.getKey();
            if (key.isEmpty()) {
                throw this.newParseException("Expected non-empty key");
            }
            this.moveToNextChar(':');
            nbtcompound.setTag(key, this.getValue());
            if (!this.hasNextComma()) break;
            if (this.withinBounds()) continue;
            throw this.newParseException("Expected key");
        }
        this.moveToNextChar('}');
        return nbtcompound;
    }

    private NBTBase createListNBT() throws NBTParseException {
        this.moveToNextChar('[');
        this.movePastWhitespace();
        if (!this.withinBounds()) {
            throw this.newParseException("Expected value");
        }
        NBTList nbtlist = new NBTList();
        byte rootType = -1;
        while (this.getCurrentChar() != ']') {
            NBTBase nbtbase = this.getValue();
            byte inputType = nbtbase.getId();
            if (rootType < 0) {
                rootType = inputType;
            } else if (inputType != rootType) {
                throw this.newParseException("Unable to insert " + nbtbase.getTypeName(inputType) + " into ListTag of type " + nbtbase.getTypeName(rootType));
            }
            nbtlist.appendTag(nbtbase);
            if (!this.hasNextComma()) break;
            if (this.withinBounds()) continue;
            throw this.newParseException("Expected value");
        }
        this.moveToNextChar(']');
        return nbtlist;
    }

    private NBTBase getArrayValue() throws NBTParseException {
        this.moveToNextChar('[');
        char identifier = this.getToNextChar();
        this.getToNextChar();
        this.movePastWhitespace();
        if (!this.withinBounds()) {
            throw this.newParseException("Expected value");
        }
        if (identifier == 'B') {
            return new NBTByteArray(this.createArrayNBT(7, 1));
        }
        return new NBTIntArray(this.createArrayNBT(11, 3));
    }

    private  List createArrayNBT(byte arrayType, byte primitiveType) throws NBTParseException {
        ArrayList arrayList = Lists.newArrayList();
        while (this.getCurrentChar() != ']') {
            NBTBase nbtbase = this.getValue();
            byte inputValue = nbtbase.getId();
            if (inputValue != primitiveType) {
                throw this.newParseException("Unable to insert " + nbtbase.getTypeName(inputValue) + " into " + nbtbase.getTypeName(arrayType));
            }
            if (primitiveType == 1) {
                arrayList.add(Byte.valueOf(((NBTPrimitive)nbtbase).getByte()));
            } else {
                arrayList.add(((NBTPrimitive)nbtbase).getInt());
            }
            if (!this.hasNextComma()) break;
            if (this.withinBounds()) continue;
            throw this.newParseException("Expected value");
        }
        this.moveToNextChar(']');
        return arrayList;
    }

    private void movePastWhitespace() {
        while (this.withinBounds() && Character.isWhitespace(this.getCurrentChar())) {
            ++this.cursor;
        }
    }

    private boolean hasNextComma() {
        this.movePastWhitespace();
        if (this.withinBounds() && this.getCurrentChar() == ',') {
            ++this.cursor;
            this.movePastWhitespace();
            return true;
        }
        return false;
    }

    private void moveToNextChar(char requiredNextChar) throws NBTParseException {
        this.movePastWhitespace();
        boolean withinBounds = this.withinBounds();
        if (withinBounds && this.getCurrentChar() == requiredNextChar) {
            ++this.cursor;
            return;
        }
        throw new NBTParseException("Expected '" + requiredNextChar + "' but got '" + (withinBounds ? Character.valueOf(this.getCurrentChar()) : "") + "'", this.inputString, this.cursor + 1);
    }

    protected boolean isValidChar(char c) {
        return c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '_' || c == '-' || c == '.' || c == '+';
    }

    private boolean cursorPlusNWithinBounds(int n) {
        return this.cursor + n < this.inputString.length();
    }

    boolean withinBounds() {
        return this.cursorPlusNWithinBounds(0);
    }

    private char getCharAtCursorPlusN(int n) {
        return this.inputString.charAt(this.cursor + n);
    }

    private char getCurrentChar() {
        return this.getCharAtCursorPlusN(0);
    }

    private char getToNextChar() {
        return this.inputString.charAt(this.cursor++);
    }
}