package com.evilco.mc.nbt.tag;

import com.evilco.mc.nbt.error.TagNotFoundException;
import com.evilco.mc.nbt.error.UnexpectedTagTypeException;
import com.evilco.mc.nbt.stream.NbtInputStream;
import com.evilco.mc.nbt.stream.NbtOutputStream;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nonnull;

public class TagCompound extends AbstractTag implements INamedTagContainer {
   protected Map<String, ITag> tags = new HashMap();

   public TagCompound(String name) {
      super(name);
   }

   public TagCompound(@Nonnull NbtInputStream inputStream, boolean anonymous) throws IOException {
      super(inputStream, anonymous);

      while(true) {
         byte type = inputStream.readByte();
         TagType tagType = TagType.valueOf(type);
         if (tagType == null) {
            throw new IOException("Could not find a tag for type ID " + type + ".");
         }

         if (tagType == TagType.END) {
            return;
         }

         this.setTag(inputStream.readTag(tagType, false));
      }
   }

   public ITag getTag(@Nonnull String name) {
      Preconditions.checkNotNull(name, "name");
      return (ITag)this.tags.get(name);
   }

   public <T extends ITag> T getTag(String name, Class<T> tagClass) throws UnexpectedTagTypeException, TagNotFoundException {
      ITag tag = this.getTag(name);
      if (tag == null) {
         throw new TagNotFoundException("The compound tag is missing a " + name + " entry");
      } else if (!tagClass.isInstance(tag)) {
         throw new UnexpectedTagTypeException("The compound entry " + name + " should be of type " + tagClass.getSimpleName() + ", but is of type " + tag.getClass().getSimpleName());
      } else {
         return tag;
      }
   }

   public TagCompound getCompound(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return (TagCompound)this.getTag(name, TagCompound.class);
   }

   public int getInteger(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagInteger)this.getTag(name, TagInteger.class)).getValue();
   }

   public short getShort(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagShort)this.getTag(name, TagShort.class)).getValue();
   }

   public byte getByte(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagByte)this.getTag(name, TagByte.class)).getValue();
   }

   public long getLong(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagLong)this.getTag(name, TagLong.class)).getValue();
   }

   public double getDouble(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagDouble)this.getTag(name, TagDouble.class)).getValue();
   }

   public float getFloat(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagFloat)this.getTag(name, TagFloat.class)).getValue();
   }

   public String getString(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagString)this.getTag(name, TagString.class)).getValue();
   }

   public <T extends ITag> List<T> getList(String name, Class<T> itemClass) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagList)this.getTag(name, TagList.class)).getTags(itemClass);
   }

   public int[] getIntegerArray(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagIntegerArray)this.getTag(name, TagIntegerArray.class)).getValues();
   }

   public byte[] getByteArray(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      return ((TagByteArray)this.getTag(name, TagByteArray.class)).getValue();
   }

   public String[] getStringArray(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      List<TagString> tags = this.getList(name, TagString.class);
      String[] array = new String[tags.size()];

      for(int i = 0; i < tags.size(); ++i) {
         array[i] = ((TagString)tags.get(i)).getValue();
      }

      return array;
   }

   public double[] getDoubleArray(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      List<TagDouble> tags = this.getList(name, TagDouble.class);
      double[] array = new double[tags.size()];

      for(int i = 0; i < tags.size(); ++i) {
         array[i] = ((TagDouble)tags.get(i)).getValue();
      }

      return array;
   }

   public float[] getFloatArray(String name) throws UnexpectedTagTypeException, TagNotFoundException {
      List<TagFloat> tags = this.getList(name, TagFloat.class);
      float[] array = new float[tags.size()];

      for(int i = 0; i < tags.size(); ++i) {
         array[i] = ((TagFloat)tags.get(i)).getValue();
      }

      return array;
   }

   public Map<String, ITag> getTags() {
      return (new ImmutableMap.Builder()).putAll(this.tags).build();
   }

   public void removeTag(@Nonnull ITag tag) {
      Preconditions.checkNotNull(tag, "tag");
      this.tags.remove(tag.getName());
   }

   public void removeTag(@Nonnull String tag) {
      Preconditions.checkNotNull(tag, "tag");
      this.tags.remove(tag);
   }

   public void setTag(@Nonnull ITag tag) {
      Preconditions.checkNotNull(tag, "tag");
      if (this.tags.containsKey(tag)) {
         ((ITag)this.tags.get(tag.getName())).setParent((ITagContainer)null);
      }

      this.tags.put(tag.getName(), tag);
      tag.setParent(this);
   }

   public byte getTagID() {
      return TagType.COMPOUND.typeID;
   }

   public void write(NbtOutputStream outputStream, boolean anonymous) throws IOException {
      super.write(outputStream, anonymous);
      Iterator var3 = this.tags.entrySet().iterator();

      while(var3.hasNext()) {
         Entry<String, ITag> tagEntry = (Entry)var3.next();
         outputStream.writeByte(((ITag)tagEntry.getValue()).getTagID());
         ((ITag)tagEntry.getValue()).write(outputStream, false);
      }

      outputStream.writeByte(TagType.END.typeID);
   }
}
