package net.minecraft.client.renderer.block.model;

import com.google.gson.JsonArray;
import com.google.common.collect.Maps;
import java.util.Locale;
import net.minecraft.util.Mth;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import net.minecraft.util.GsonHelper;
import com.google.gson.JsonDeserializationContext;
import java.lang.reflect.Type;
import com.google.gson.JsonElement;
import com.google.gson.JsonDeserializer;
import java.util.Iterator;
import javax.annotation.Nullable;
import net.minecraft.core.Direction;
import java.util.Map;
import com.mojang.math.Vector3f;

public class BlockElement {
    public final Vector3f from;
    public final Vector3f to;
    public final Map<Direction, BlockElementFace> faces;
    public final BlockElementRotation rotation;
    public final boolean shade;
    
    public BlockElement(final Vector3f e1, final Vector3f e2, final Map<Direction, BlockElementFace> map, @Nullable final BlockElementRotation drq, final boolean boolean5) {
        this.from = e1;
        this.to = e2;
        this.faces = map;
        this.rotation = drq;
        this.shade = boolean5;
        this.fillUvs();
    }
    
    private void fillUvs() {
        for (final Map.Entry<Direction, BlockElementFace> entry3 : this.faces.entrySet()) {
            final float[] arr4 = this.uvsByFace(entry3.getKey());
            entry3.getValue().uv.setMissingUv(arr4);
        }
    }
    
    private float[] uvsByFace(final Direction fp) {
        switch (fp) {
            case DOWN: {
                return new float[] { this.from.x(), 16.0f - this.to.z(), this.to.x(), 16.0f - this.from.z() };
            }
            case UP: {
                return new float[] { this.from.x(), this.from.z(), this.to.x(), this.to.z() };
            }
            default: {
                return new float[] { 16.0f - this.to.x(), 16.0f - this.to.y(), 16.0f - this.from.x(), 16.0f - this.from.y() };
            }
            case SOUTH: {
                return new float[] { this.from.x(), 16.0f - this.to.y(), this.to.x(), 16.0f - this.from.y() };
            }
            case WEST: {
                return new float[] { this.from.z(), 16.0f - this.to.y(), this.to.z(), 16.0f - this.from.y() };
            }
            case EAST: {
                return new float[] { 16.0f - this.to.z(), 16.0f - this.to.y(), 16.0f - this.from.z(), 16.0f - this.from.y() };
            }
        }
    }
    
    public static class Deserializer implements JsonDeserializer<BlockElement> {
        protected Deserializer() {
        }
        
        @Override
        public BlockElement deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
            final JsonObject jsonObject5 = jsonElement.getAsJsonObject();
            final Vector3f e6 = this.getFrom(jsonObject5);
            final Vector3f e7 = this.getTo(jsonObject5);
            final BlockElementRotation drq8 = this.getRotation(jsonObject5);
            final Map<Direction, BlockElementFace> map9 = this.getFaces(jsonDeserializationContext, jsonObject5);
            if (jsonObject5.has("shade") && !GsonHelper.isBooleanValue(jsonObject5, "shade")) {
                throw new JsonParseException("Expected shade to be a Boolean");
            }
            final boolean boolean10 = GsonHelper.getAsBoolean(jsonObject5, "shade", true);
            return new BlockElement(e6, e7, map9, drq8, boolean10);
        }
        
        @Nullable
        private BlockElementRotation getRotation(final JsonObject jsonObject) {
            BlockElementRotation drq3 = null;
            if (jsonObject.has("rotation")) {
                final JsonObject jsonObject2 = GsonHelper.getAsJsonObject(jsonObject, "rotation");
                final Vector3f e5 = this.getVector3f(jsonObject2, "origin");
                e5.mul(0.0625f);
                final Direction.Axis a6 = this.getAxis(jsonObject2);
                final float float7 = this.getAngle(jsonObject2);
                final boolean boolean8 = GsonHelper.getAsBoolean(jsonObject2, "rescale", false);
                drq3 = new BlockElementRotation(e5, a6, float7, boolean8);
            }
            return drq3;
        }
        
        private float getAngle(final JsonObject jsonObject) {
            final float float3 = GsonHelper.getAsFloat(jsonObject, "angle");
            if (float3 != 0.0f && Mth.abs(float3) != 22.5f && Mth.abs(float3) != 45.0f) {
                throw new JsonParseException("Invalid rotation " + float3 + " found, only -45/-22.5/0/22.5/45 allowed");
            }
            return float3;
        }
        
        private Direction.Axis getAxis(final JsonObject jsonObject) {
            final String string3 = GsonHelper.getAsString(jsonObject, "axis");
            final Direction.Axis a4 = Direction.Axis.byName(string3.toLowerCase(Locale.ROOT));
            if (a4 == null) {
                throw new JsonParseException("Invalid rotation axis: " + string3);
            }
            return a4;
        }
        
        private Map<Direction, BlockElementFace> getFaces(final JsonDeserializationContext jsonDeserializationContext, final JsonObject jsonObject) {
            final Map<Direction, BlockElementFace> map4 = this.filterNullFromFaces(jsonDeserializationContext, jsonObject);
            if (map4.isEmpty()) {
                throw new JsonParseException("Expected between 1 and 6 unique faces, got 0");
            }
            return map4;
        }
        
        private Map<Direction, BlockElementFace> filterNullFromFaces(final JsonDeserializationContext jsonDeserializationContext, final JsonObject jsonObject) {
            final Map<Direction, BlockElementFace> map4 = Maps.newEnumMap(Direction.class);
            final JsonObject jsonObject2 = GsonHelper.getAsJsonObject(jsonObject, "faces");
            for (final Map.Entry<String, JsonElement> entry7 : jsonObject2.entrySet()) {
                final Direction fp8 = this.getFacing(entry7.getKey());
                map4.put(fp8, jsonDeserializationContext.<BlockElementFace>deserialize(entry7.getValue(), BlockElementFace.class));
            }
            return map4;
        }
        
        private Direction getFacing(final String string) {
            final Direction fp3 = Direction.byName(string);
            if (fp3 == null) {
                throw new JsonParseException("Unknown facing: " + string);
            }
            return fp3;
        }
        
        private Vector3f getTo(final JsonObject jsonObject) {
            final Vector3f e3 = this.getVector3f(jsonObject, "to");
            if (e3.x() < -16.0f || e3.y() < -16.0f || e3.z() < -16.0f || e3.x() > 32.0f || e3.y() > 32.0f || e3.z() > 32.0f) {
                throw new JsonParseException("'to' specifier exceeds the allowed boundaries: " + e3);
            }
            return e3;
        }
        
        private Vector3f getFrom(final JsonObject jsonObject) {
            final Vector3f e3 = this.getVector3f(jsonObject, "from");
            if (e3.x() < -16.0f || e3.y() < -16.0f || e3.z() < -16.0f || e3.x() > 32.0f || e3.y() > 32.0f || e3.z() > 32.0f) {
                throw new JsonParseException("'from' specifier exceeds the allowed boundaries: " + e3);
            }
            return e3;
        }
        
        private Vector3f getVector3f(final JsonObject jsonObject, final String string) {
            final JsonArray jsonArray4 = GsonHelper.getAsJsonArray(jsonObject, string);
            if (jsonArray4.size() != 3) {
                throw new JsonParseException("Expected 3 " + string + " values, found: " + jsonArray4.size());
            }
            final float[] arr5 = new float[3];
            for (int integer6 = 0; integer6 < arr5.length; ++integer6) {
                arr5[integer6] = GsonHelper.convertToFloat(jsonArray4.get(integer6), string + "[" + integer6 + "]");
            }
            return new Vector3f(arr5[0], arr5[1], arr5[2]);
        }
    }
}
