package net.minecraft.nbt;

import java.util.Collection;
import it.unimi.dsi.fastutil.bytes.ByteOpenHashSet;
import java.util.Arrays;
import java.io.DataInput;
import net.minecraft.network.chat.MutableComponent;
import com.google.common.base.Strings;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.Component;
import java.util.Objects;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import java.io.IOException;
import java.util.Iterator;
import java.io.DataOutput;
import com.google.common.collect.Lists;
import java.util.List;
import it.unimi.dsi.fastutil.bytes.ByteSet;

public class ListTag extends CollectionTag<Tag> {
    public static final TagType<ListTag> TYPE;
    private static final ByteSet INLINE_ELEMENT_TYPES;
    private final List<Tag> list;
    private byte type;
    
    private ListTag(final List<Tag> list, final byte byte2) {
        this.list = list;
        this.type = byte2;
    }
    
    public ListTag() {
        this(Lists.newArrayList(), (byte)0);
    }
    
    @Override
    public void write(final DataOutput dataOutput) throws IOException {
        if (this.list.isEmpty()) {
            this.type = 0;
        }
        else {
            this.type = this.list.get(0).getId();
        }
        dataOutput.writeByte(this.type);
        dataOutput.writeInt(this.list.size());
        for (final Tag lu4 : this.list) {
            lu4.write(dataOutput);
        }
    }
    
    @Override
    public byte getId() {
        return 9;
    }
    
    @Override
    public TagType<ListTag> getType() {
        return ListTag.TYPE;
    }
    
    @Override
    public String toString() {
        final StringBuilder stringBuilder2 = new StringBuilder("[");
        for (int integer3 = 0; integer3 < this.list.size(); ++integer3) {
            if (integer3 != 0) {
                stringBuilder2.append(',');
            }
            stringBuilder2.append(this.list.get(integer3));
        }
        return stringBuilder2.append(']').toString();
    }
    
    private void updateTypeAfterRemove() {
        if (this.list.isEmpty()) {
            this.type = 0;
        }
    }
    
    @Override
    public Tag remove(final int integer) {
        final Tag lu3 = this.list.remove(integer);
        this.updateTypeAfterRemove();
        return lu3;
    }
    
    @Override
    public boolean isEmpty() {
        return this.list.isEmpty();
    }
    
    public CompoundTag getCompound(final int integer) {
        if (integer >= 0 && integer < this.list.size()) {
            final Tag lu3 = this.list.get(integer);
            if (lu3.getId() == 10) {
                return (CompoundTag)lu3;
            }
        }
        return new CompoundTag();
    }
    
    public ListTag getList(final int integer) {
        if (integer >= 0 && integer < this.list.size()) {
            final Tag lu3 = this.list.get(integer);
            if (lu3.getId() == 9) {
                return (ListTag)lu3;
            }
        }
        return new ListTag();
    }
    
    public short getShort(final int integer) {
        if (integer >= 0 && integer < this.list.size()) {
            final Tag lu3 = this.list.get(integer);
            if (lu3.getId() == 2) {
                return ((ShortTag)lu3).getAsShort();
            }
        }
        return 0;
    }
    
    public int getInt(final int integer) {
        if (integer >= 0 && integer < this.list.size()) {
            final Tag lu3 = this.list.get(integer);
            if (lu3.getId() == 3) {
                return ((IntTag)lu3).getAsInt();
            }
        }
        return 0;
    }
    
    public int[] getIntArray(final int integer) {
        if (integer >= 0 && integer < this.list.size()) {
            final Tag lu3 = this.list.get(integer);
            if (lu3.getId() == 11) {
                return ((IntArrayTag)lu3).getAsIntArray();
            }
        }
        return new int[0];
    }
    
    public double getDouble(final int integer) {
        if (integer >= 0 && integer < this.list.size()) {
            final Tag lu3 = this.list.get(integer);
            if (lu3.getId() == 6) {
                return ((DoubleTag)lu3).getAsDouble();
            }
        }
        return 0.0;
    }
    
    public float getFloat(final int integer) {
        if (integer >= 0 && integer < this.list.size()) {
            final Tag lu3 = this.list.get(integer);
            if (lu3.getId() == 5) {
                return ((FloatTag)lu3).getAsFloat();
            }
        }
        return 0.0f;
    }
    
    public String getString(final int integer) {
        if (integer < 0 || integer >= this.list.size()) {
            return "";
        }
        final Tag lu3 = this.list.get(integer);
        if (lu3.getId() == 8) {
            return lu3.getAsString();
        }
        return lu3.toString();
    }
    
    @Override
    public int size() {
        return this.list.size();
    }
    
    @Override
    public Tag get(final int integer) {
        return this.list.get(integer);
    }
    
    @Override
    public Tag set(final int integer, final Tag lu) {
        final Tag lu2 = this.get(integer);
        if (!this.setTag(integer, lu)) {
            throw new UnsupportedOperationException(String.format("Trying to add tag of type %d to list of %d", lu.getId(), this.type));
        }
        return lu2;
    }
    
    @Override
    public void add(final int integer, final Tag lu) {
        if (!this.addTag(integer, lu)) {
            throw new UnsupportedOperationException(String.format("Trying to add tag of type %d to list of %d", lu.getId(), this.type));
        }
    }
    
    @Override
    public boolean setTag(final int integer, final Tag lu) {
        if (this.updateType(lu)) {
            this.list.set(integer, lu);
            return true;
        }
        return false;
    }
    
    @Override
    public boolean addTag(final int integer, final Tag lu) {
        if (this.updateType(lu)) {
            this.list.add(integer, lu);
            return true;
        }
        return false;
    }
    
    private boolean updateType(final Tag lu) {
        if (lu.getId() == 0) {
            return false;
        }
        if (this.type == 0) {
            this.type = lu.getId();
            return true;
        }
        return this.type == lu.getId();
    }
    
    @Override
    public ListTag copy() {
        final Iterable<Tag> iterable2 = TagTypes.getType(this.type).isValue() ? this.list : Iterables.<Tag, Tag>transform((Iterable<Tag>)this.list, Tag::copy);
        final List<Tag> list3 = Lists.newArrayList(iterable2);
        return new ListTag(list3, this.type);
    }
    
    @Override
    public boolean equals(final Object object) {
        return this == object || (object instanceof ListTag && Objects.equals(this.list, ((ListTag)object).list));
    }
    
    @Override
    public int hashCode() {
        return this.list.hashCode();
    }
    
    @Override
    public Component getPrettyDisplay(final String string, final int integer) {
        if (this.isEmpty()) {
            return new TextComponent("[]");
        }
        if (ListTag.INLINE_ELEMENT_TYPES.contains(this.type) && this.size() <= 8) {
            final String string2 = ", ";
            final MutableComponent mx5 = new TextComponent("[");
            for (int integer2 = 0; integer2 < this.list.size(); ++integer2) {
                if (integer2 != 0) {
                    mx5.append(", ");
                }
                mx5.append(this.list.get(integer2).getPrettyDisplay());
            }
            mx5.append("]");
            return mx5;
        }
        final MutableComponent mx6 = new TextComponent("[");
        if (!string.isEmpty()) {
            mx6.append("\n");
        }
        final String string3 = String.valueOf(',');
        for (int integer2 = 0; integer2 < this.list.size(); ++integer2) {
            final MutableComponent mx7 = new TextComponent(Strings.repeat(string, integer + 1));
            mx7.append(this.list.get(integer2).getPrettyDisplay(string, integer + 1));
            if (integer2 != this.list.size() - 1) {
                mx7.append(string3).append(string.isEmpty() ? " " : "\n");
            }
            mx6.append(mx7);
        }
        if (!string.isEmpty()) {
            mx6.append("\n").append(Strings.repeat(string, integer));
        }
        mx6.append("]");
        return mx6;
    }
    
    @Override
    public byte getElementType() {
        return this.type;
    }
    
    @Override
    public void clear() {
        this.list.clear();
        this.type = 0;
    }
    
    static {
        TYPE = new TagType<ListTag>() {
            @Override
            public ListTag load(final DataInput dataInput, final int integer, final NbtAccounter ln) throws IOException {
                ln.accountBits(296L);
                if (integer > 512) {
                    throw new RuntimeException("Tried to read NBT tag with too high complexity, depth > 512");
                }
                final byte byte5 = dataInput.readByte();
                final int integer2 = dataInput.readInt();
                if (byte5 == 0 && integer2 > 0) {
                    throw new RuntimeException("Missing type on ListTag");
                }
                ln.accountBits(32L * integer2);
                final TagType<?> lw7 = TagTypes.getType(byte5);
                final List<Tag> list8 = Lists.newArrayListWithCapacity(integer2);
                for (int integer3 = 0; integer3 < integer2; ++integer3) {
                    list8.add((Tag)lw7.load(dataInput, integer + 1, ln));
                }
                return new ListTag(list8, byte5, null);
            }
            
            @Override
            public String getName() {
                return "LIST";
            }
            
            @Override
            public String getPrettyName() {
                return "TAG_List";
            }
        };
        INLINE_ELEMENT_TYPES = (ByteSet)new ByteOpenHashSet((Collection)Arrays.<Byte>asList(1, 2, 3, 4, 5, 6));
    }
}
