package net.minecraft.advancements;

import org.apache.commons.lang3.ArrayUtils;
import com.google.gson.JsonSyntaxException;
import net.minecraft.util.GsonHelper;
import net.minecraft.advancements.critereon.DeserializationContext;
import net.minecraft.network.FriendlyByteBuf;
import java.util.Iterator;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.function.Consumer;
import java.util.Collection;
import java.util.function.Function;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.ItemStack;
import com.google.common.collect.Maps;
import java.util.Arrays;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.HoverEvent;
import net.minecraft.network.chat.ComponentUtils;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextComponent;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import javax.annotation.Nullable;
import net.minecraft.network.chat.Component;
import java.util.Set;
import java.util.Map;
import net.minecraft.resources.ResourceLocation;

public class Advancement {
    private final Advancement parent;
    private final DisplayInfo display;
    private final AdvancementRewards rewards;
    private final ResourceLocation id;
    private final Map<String, Criterion> criteria;
    private final String[][] requirements;
    private final Set<Advancement> children;
    private final Component chatComponent;
    
    public Advancement(final ResourceLocation uh, @Nullable final Advancement w, @Nullable final DisplayInfo af, final AdvancementRewards z, final Map<String, Criterion> map, final String[][] arr) {
        this.children = Sets.newLinkedHashSet();
        this.id = uh;
        this.display = af;
        this.criteria = ImmutableMap.copyOf(map);
        this.parent = w;
        this.rewards = z;
        this.requirements = arr;
        if (w != null) {
            w.addChild(this);
        }
        if (af == null) {
            this.chatComponent = new TextComponent(uh.toString());
        }
        else {
            final Component mr8 = af.getTitle();
            final ChatFormatting i9 = af.getFrame().getChatColor();
            final Component mr9 = ComponentUtils.mergeStyles(mr8.copy(), Style.EMPTY.withColor(i9)).append("\n").append(af.getDescription());
            final Component mr10 = mr8.copy().withStyle(nb -> nb.withHoverEvent(new HoverEvent((HoverEvent.Action<T>)HoverEvent.Action.SHOW_TEXT, (T)mr9)));
            this.chatComponent = new TextComponent("[").append(mr10).append("]").withStyle(i9);
        }
    }
    
    public Builder deconstruct() {
        return new Builder((this.parent == null) ? null : this.parent.getId(), this.display, this.rewards, (Map)this.criteria, this.requirements);
    }
    
    @Nullable
    public Advancement getParent() {
        return this.parent;
    }
    
    @Nullable
    public DisplayInfo getDisplay() {
        return this.display;
    }
    
    public AdvancementRewards getRewards() {
        return this.rewards;
    }
    
    @Override
    public String toString() {
        return "SimpleAdvancement{id=" + this.getId() + ", parent=" + ((this.parent == null) ? "null" : this.parent.getId()) + ", display=" + this.display + ", rewards=" + this.rewards + ", criteria=" + this.criteria + ", requirements=" + Arrays.deepToString(this.requirements) + '}';
    }
    
    public Iterable<Advancement> getChildren() {
        return this.children;
    }
    
    public Map<String, Criterion> getCriteria() {
        return this.criteria;
    }
    
    public int getMaxCriteraRequired() {
        return this.requirements.length;
    }
    
    public void addChild(final Advancement w) {
        this.children.add(w);
    }
    
    public ResourceLocation getId() {
        return this.id;
    }
    
    @Override
    public boolean equals(final Object object) {
        if (this == object) {
            return true;
        }
        if (!(object instanceof Advancement)) {
            return false;
        }
        final Advancement w3 = (Advancement)object;
        return this.id.equals(w3.id);
    }
    
    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
    
    public String[][] getRequirements() {
        return this.requirements;
    }
    
    public Component getChatComponent() {
        return this.chatComponent;
    }
    
    public static class Builder {
        private ResourceLocation parentId;
        private Advancement parent;
        private DisplayInfo display;
        private AdvancementRewards rewards;
        private Map<String, Criterion> criteria;
        private String[][] requirements;
        private RequirementsStrategy requirementsStrategy;
        
        private Builder(@Nullable final ResourceLocation uh, @Nullable final DisplayInfo af, final AdvancementRewards z, final Map<String, Criterion> map, final String[][] arr) {
            this.rewards = AdvancementRewards.EMPTY;
            this.criteria = Maps.newLinkedHashMap();
            this.requirementsStrategy = RequirementsStrategy.AND;
            this.parentId = uh;
            this.display = af;
            this.rewards = z;
            this.criteria = map;
            this.requirements = arr;
        }
        
        private Builder() {
            this.rewards = AdvancementRewards.EMPTY;
            this.criteria = Maps.newLinkedHashMap();
            this.requirementsStrategy = RequirementsStrategy.AND;
        }
        
        public static Builder advancement() {
            return new Builder();
        }
        
        public Builder parent(final Advancement w) {
            this.parent = w;
            return this;
        }
        
        public Builder parent(final ResourceLocation uh) {
            this.parentId = uh;
            return this;
        }
        
        public Builder display(final ItemStack bki, final Component mr2, final Component mr3, @Nullable final ResourceLocation uh, final FrameType ag, final boolean boolean6, final boolean boolean7, final boolean boolean8) {
            return this.display(new DisplayInfo(bki, mr2, mr3, uh, ag, boolean6, boolean7, boolean8));
        }
        
        public Builder display(final ItemLike bqa, final Component mr2, final Component mr3, @Nullable final ResourceLocation uh, final FrameType ag, final boolean boolean6, final boolean boolean7, final boolean boolean8) {
            return this.display(new DisplayInfo(new ItemStack(bqa.asItem()), mr2, mr3, uh, ag, boolean6, boolean7, boolean8));
        }
        
        public Builder display(final DisplayInfo af) {
            this.display = af;
            return this;
        }
        
        public Builder rewards(final AdvancementRewards.Builder a) {
            return this.rewards(a.build());
        }
        
        public Builder rewards(final AdvancementRewards z) {
            this.rewards = z;
            return this;
        }
        
        public Builder addCriterion(final String string, final CriterionTriggerInstance ae) {
            return this.addCriterion(string, new Criterion(ae));
        }
        
        public Builder addCriterion(final String string, final Criterion ab) {
            if (this.criteria.containsKey(string)) {
                throw new IllegalArgumentException("Duplicate criterion " + string);
            }
            this.criteria.put(string, ab);
            return this;
        }
        
        public Builder requirements(final RequirementsStrategy ah) {
            this.requirementsStrategy = ah;
            return this;
        }
        
        public boolean canBuild(final Function<ResourceLocation, Advancement> function) {
            if (this.parentId == null) {
                return true;
            }
            if (this.parent == null) {
                this.parent = function.apply(this.parentId);
            }
            return this.parent != null;
        }
        
        public Advancement build(final ResourceLocation uh) {
            if (!this.canBuild(uh -> null)) {
                throw new IllegalStateException("Tried to build incomplete advancement!");
            }
            if (this.requirements == null) {
                this.requirements = this.requirementsStrategy.createRequirements(this.criteria.keySet());
            }
            return new Advancement(uh, this.parent, this.display, this.rewards, this.criteria, this.requirements);
        }
        
        public Advancement save(final Consumer<Advancement> consumer, final String string) {
            final Advancement w4 = this.build(new ResourceLocation(string));
            consumer.accept(w4);
            return w4;
        }
        
        public JsonObject serializeToJson() {
            if (this.requirements == null) {
                this.requirements = this.requirementsStrategy.createRequirements(this.criteria.keySet());
            }
            final JsonObject jsonObject2 = new JsonObject();
            if (this.parent != null) {
                jsonObject2.addProperty("parent", this.parent.getId().toString());
            }
            else if (this.parentId != null) {
                jsonObject2.addProperty("parent", this.parentId.toString());
            }
            if (this.display != null) {
                jsonObject2.add("display", this.display.serializeToJson());
            }
            jsonObject2.add("rewards", this.rewards.serializeToJson());
            final JsonObject jsonObject3 = new JsonObject();
            for (final Map.Entry<String, Criterion> entry5 : this.criteria.entrySet()) {
                jsonObject3.add(entry5.getKey(), entry5.getValue().serializeToJson());
            }
            jsonObject2.add("criteria", jsonObject3);
            final JsonArray jsonArray4 = new JsonArray();
            for (final String[] arr8 : this.requirements) {
                final JsonArray jsonArray5 = new JsonArray();
                for (final String string13 : arr8) {
                    jsonArray5.add(string13);
                }
                jsonArray4.add(jsonArray5);
            }
            jsonObject2.add("requirements", jsonArray4);
            return jsonObject2;
        }
        
        public void serializeToNetwork(final FriendlyByteBuf mg) {
            if (this.parentId == null) {
                mg.writeBoolean(false);
            }
            else {
                mg.writeBoolean(true);
                mg.writeResourceLocation(this.parentId);
            }
            if (this.display == null) {
                mg.writeBoolean(false);
            }
            else {
                mg.writeBoolean(true);
                this.display.serializeToNetwork(mg);
            }
            Criterion.serializeToNetwork(this.criteria, mg);
            mg.writeVarInt(this.requirements.length);
            for (final String[] arr6 : this.requirements) {
                mg.writeVarInt(arr6.length);
                for (final String string10 : arr6) {
                    mg.writeUtf(string10);
                }
            }
        }
        
        @Override
        public String toString() {
            return "Task Advancement{parentId=" + this.parentId + ", display=" + this.display + ", rewards=" + this.rewards + ", criteria=" + this.criteria + ", requirements=" + Arrays.deepToString(this.requirements) + '}';
        }
        
        public static Builder fromJson(final JsonObject jsonObject, final DeserializationContext av) {
            final ResourceLocation uh3 = jsonObject.has("parent") ? new ResourceLocation(GsonHelper.getAsString(jsonObject, "parent")) : null;
            final DisplayInfo af4 = jsonObject.has("display") ? DisplayInfo.fromJson(GsonHelper.getAsJsonObject(jsonObject, "display")) : null;
            final AdvancementRewards z5 = jsonObject.has("rewards") ? AdvancementRewards.deserialize(GsonHelper.getAsJsonObject(jsonObject, "rewards")) : AdvancementRewards.EMPTY;
            final Map<String, Criterion> map6 = Criterion.criteriaFromJson(GsonHelper.getAsJsonObject(jsonObject, "criteria"), av);
            if (map6.isEmpty()) {
                throw new JsonSyntaxException("Advancement criteria cannot be empty");
            }
            final JsonArray jsonArray7 = GsonHelper.getAsJsonArray(jsonObject, "requirements", new JsonArray());
            String[][] arr8 = new String[jsonArray7.size()][];
            for (int integer9 = 0; integer9 < jsonArray7.size(); ++integer9) {
                final JsonArray jsonArray8 = GsonHelper.convertToJsonArray(jsonArray7.get(integer9), "requirements[" + integer9 + "]");
                arr8[integer9] = new String[jsonArray8.size()];
                for (int integer10 = 0; integer10 < jsonArray8.size(); ++integer10) {
                    arr8[integer9][integer10] = GsonHelper.convertToString(jsonArray8.get(integer10), "requirements[" + integer9 + "][" + integer10 + "]");
                }
            }
            if (arr8.length == 0) {
                arr8 = new String[map6.size()][];
                int integer9 = 0;
                for (final String string11 : map6.keySet()) {
                    arr8[integer9++] = new String[] { string11 };
                }
            }
            for (final String[] arr9 : arr8) {
                if (arr9.length == 0 && map6.isEmpty()) {
                    throw new JsonSyntaxException("Requirement entry cannot be empty");
                }
                for (final String string12 : arr9) {
                    if (!map6.containsKey(string12)) {
                        throw new JsonSyntaxException("Unknown required criterion '" + string12 + "'");
                    }
                }
            }
            for (final String string13 : map6.keySet()) {
                boolean boolean11 = false;
                for (final String[] arr10 : arr8) {
                    if (ArrayUtils.contains((Object[])arr10, string13)) {
                        boolean11 = true;
                        break;
                    }
                }
                if (!boolean11) {
                    throw new JsonSyntaxException("Criterion '" + string13 + "' isn't a requirement for completion. This isn't supported behaviour, all criteria must be required.");
                }
            }
            return new Builder(uh3, af4, z5, map6, arr8);
        }
        
        public static Builder fromNetwork(final FriendlyByteBuf mg) {
            final ResourceLocation uh2 = mg.readBoolean() ? mg.readResourceLocation() : null;
            final DisplayInfo af3 = mg.readBoolean() ? DisplayInfo.fromNetwork(mg) : null;
            final Map<String, Criterion> map4 = Criterion.criteriaFromNetwork(mg);
            final String[][] arr5 = new String[mg.readVarInt()][];
            for (int integer6 = 0; integer6 < arr5.length; ++integer6) {
                arr5[integer6] = new String[mg.readVarInt()];
                for (int integer7 = 0; integer7 < arr5[integer6].length; ++integer7) {
                    arr5[integer6][integer7] = mg.readUtf(32767);
                }
            }
            return new Builder(uh2, af3, AdvancementRewards.EMPTY, map4, arr5);
        }
        
        public Map<String, Criterion> getCriteria() {
            return this.criteria;
        }
    }
}
