// Date: 5/18/2012 11:45:03 PM
// Template version 1.1
// Java generated by Techne
// Keep in mind that you still need to fill in some blanks
// - ZeuX

package twilightforest.client.model.entity;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.HierarchicalModel;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.*;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.animal.Sheep;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemDisplayContext;
import twilightforest.client.JappaPackReloadListener;
import twilightforest.client.renderer.entity.QuestRamRenderer;
import twilightforest.entity.passive.QuestRam;

import java.util.Arrays;

public class QuestRamModel<T extends QuestRam> extends HierarchicalModel<T> implements TrophyBlockModel {

	private final ModelPart root;
	private final ModelPart head;
	private ModelPart neck;
	private ModelPart frontTorso;
	private ModelPart backTorso;
	private ModelPart leftFrontLeg;
	private ModelPart rightFrontLeg;
	private ModelPart leftBackLeg;
	private ModelPart rightBackLeg;
	private final ModelPart[] segments = new ModelPart[16];

	final int[] colorOrder = new int[]{0, 8, 7, 15, 14, 1, 4, 5, 13, 3, 9, 11, 10, 2, 6, 12};

	public QuestRamModel(ModelPart root) {
		this.root = root;
		this.head = root.getChild("head");
		if (root.hasChild("neck")) {
			this.neck = root.getChild("neck");
			this.frontTorso = root.getChild("front_torso");
			this.backTorso = root.getChild("back_torso");
			this.leftFrontLeg = root.getChild("left_front_leg");
			this.rightFrontLeg = root.getChild("right_front_leg");
			this.leftBackLeg = root.getChild("left_back_leg");
			this.rightBackLeg = root.getChild("right_back_leg");
			Arrays.setAll(this.segments, (num) -> root.getChild(getSegmentName(num)));
			for (int i = 0; i < 16; i++) {
				this.segments[i].visible = false;
			}
		}
	}

	public static LayerDefinition checkForPack() {
		return JappaPackReloadListener.INSTANCE.isJappaPackLoaded() ? createJappaModel() : create();
	}

	public static LayerDefinition checkForPackTrophyEdition() {
		return JappaPackReloadListener.INSTANCE.isJappaPackLoaded() ? createJappaTrophy() : create();
	}

	private static LayerDefinition create() {
		MeshDefinition meshdefinition = new MeshDefinition();
		PartDefinition partdefinition = meshdefinition.getRoot();

		PartDefinition head = partdefinition.addOrReplaceChild("head", CubeListBuilder.create().texOffs(0, 70).addBox(-6.0F, -5.0F, -11.0F, 12.0F, 9.0F, 15.0F), PartPose.offset(0.0F, -12.0F, -11.0F));

		head.addOrReplaceChild("sloped_head", CubeListBuilder.create()
				.texOffs(54, 73)
				.addBox(-10.0F, -8.5F, -0.5F, 11.0F, 9.0F, 12.0F),
			PartPose.offsetAndRotation(4.5F, 2.0F, -6.0F, 0.5236F, 0.0F, 0.0F));

		head.addOrReplaceChild("left_horn", CubeListBuilder.create()
				.texOffs(0, 94)
				.addBox(5.0F, -45.0F, -14.0F, 4.0F, 4.0F, 6.0F)
				.texOffs(20, 96)
				.addBox(8.0F, -44.0F, -9.0F, 3.0F, 4.0F, 4.0F)
				.texOffs(34, 95)
				.addBox(9.0F, -42.0F, -7.0F, 3.0F, 6.0F, 3.0F)
				.texOffs(46, 98)
				.addBox(10.5F, -38.0F, -9.0F, 3.0F, 3.0F, 3.0F)
				.texOffs(58, 95)
				.addBox(12.0F, -36.0F, -14.0F, 3.0F, 3.0F, 6.0F)
				.texOffs(76, 95)
				.addBox(13.0F, -40.0F, -16.0F, 3.0F, 6.0F, 3.0F)
				.texOffs(88, 97)
				.addBox(14.0F, -42.0F, -14.0F, 3.0F, 3.0F, 4.0F),
			PartPose.offset(0.0F, 36.0F, 11.0F));

		head.addOrReplaceChild("right_horn", CubeListBuilder.create().mirror()
				.texOffs(0, 94)
				.addBox(-9.0F, -45.0F, -14.0F, 4.0F, 4.0F, 6.0F)
				.texOffs(20, 96)
				.addBox(-11.0F, -44.0F, -9.0F, 3.0F, 4.0F, 4.0F)
				.texOffs(34, 95)
				.addBox(-12.0F, -42.0F, -7.0F, 3.0F, 6.0F, 3.0F)
				.texOffs(46, 98)
				.addBox(-13.5F, -38.0F, -9.0F, 3.0F, 3.0F, 3.0F)
				.texOffs(58, 95)
				.addBox(-15.0F, -36.0F, -14.0F, 3.0F, 3.0F, 6.0F)
				.texOffs(76, 95)
				.addBox(-16.0F, -40.0F, -16.0F, 3.0F, 6.0F, 3.0F)
				.texOffs(88, 97)
				.addBox(-17.0F, -42.0F, -14.0F, 3.0F, 3.0F, 4.0F),
			PartPose.offset(0.0F, 36.0F, 11.0F));

		PartDefinition neck = partdefinition.addOrReplaceChild("neck", CubeListBuilder.create(),
			PartPose.offset(0.0F, -8.0F, -11.0F));

		neck.addOrReplaceChild("neck_r1", CubeListBuilder.create()
				.texOffs(66, 37)
				.addBox(-9.5F, -14.0F, -1.0F, 11.0F, 14.0F, 12.0F, new CubeDeformation(-0.001F)),
			PartPose.offsetAndRotation(4.0F, 8.0F, -3.0F, 0.2618F, 0.0F, 0.0F));

		partdefinition.addOrReplaceChild("front_torso", CubeListBuilder.create()
				.texOffs(0, 0)
				.addBox(-9.0F, -32.0F, -15.0F, 18.0F, 15.0F, 15.0F),
			PartPose.offset(0.0F, 24.0F, 0.0F));

		partdefinition.addOrReplaceChild("back_torso", CubeListBuilder.create()
				.texOffs(0, 30)
				.addBox(-9.0F, -32.0F, 0.0F, 18.0F, 15.0F, 15.0F),
			PartPose.offset(0.0F, 24.0F, 0.0F));

		partdefinition.addOrReplaceChild("left_front_leg", CubeListBuilder.create()
				.texOffs(90, 20)
				.addBox(-3.5F, -5.5F, -3.5F, 7.0F, 10.0F, 7.0F)
				.texOffs(66, 18)
				.addBox(-3.0F, 4.0F, -3.0F, 6.0F, 13.0F, 6.0F),
			PartPose.offset(6.0F, 7.0F, -10.5F));

		partdefinition.addOrReplaceChild("right_front_leg", CubeListBuilder.create().mirror()
				.texOffs(90, 20)
				.addBox(-3.5F, -5.5F, -3.5F, 7.0F, 10.0F, 7.0F)
				.texOffs(66, 18)
				.addBox(-3.0F, 4.0F, -3.0F, 6.0F, 13.0F, 6.0F),
			PartPose.offset(-6.0F, 7.0F, -10.5F));

		partdefinition.addOrReplaceChild("left_back_leg", CubeListBuilder.create()
				.texOffs(90, 0)
				.addBox(-3.5F, -4.5F, -6.0F, 7.0F, 10.0F, 10.0F)
				.texOffs(66, 0)
				.addBox(-3.0F, 5.0F, -3.0F, 6.0F, 12.0F, 6.0F),
			PartPose.offset(6.0F, 7.0F, 9.0F));

		partdefinition.addOrReplaceChild("right_back_leg", CubeListBuilder.create().mirror()
				.texOffs(90, 0)
				.addBox(-3.5F, -4.5F, -6.0F, 7.0F, 10.0F, 10.0F)
				.texOffs(66, 0)
				.addBox(-3.0F, 5.0F, -3.0F, 6.0F, 12.0F, 6.0F),
			PartPose.offset(-6.0F, 7.0F, 9.0F));

		CubeListBuilder wool = CubeListBuilder.create()
			.texOffs(0, 104)
			.addBox(-9F, -7.5F, 0.0F, 18.0F, 15.0F, 2.0F);

		for (int i = 0; i < 16; i++) {
			partdefinition.addOrReplaceChild(getSegmentName(i), wool, PartPose.offset(0.0F, -0.5F, 0.0F));
		}

		return LayerDefinition.create(meshdefinition, 128, 128);
	}

	private static LayerDefinition createJappaModel() {
		MeshDefinition meshdefinition = new MeshDefinition();
		PartDefinition partdefinition = meshdefinition.getRoot();

		//these ARE actually the horns, theyre just called the head so its rendered properly as a trophy
		var horns = partdefinition.addOrReplaceChild("head", CubeListBuilder.create()
				.texOffs(64, 0)
				.addBox(-9.0F, -11.0F, -1.0F, 4.0F, 10.0F, 10.0F)
				.texOffs(48, 0)
				.addBox(-13.0F, -11.0F, 5.0F, 4.0F, 4.0F, 4.0F)
				.texOffs(92, 0)
				.addBox(5.0F, -11.0F, -1.0F, 4.0F, 10.0F, 10.0F)
				.texOffs(110, 0)
				.addBox(9.0F, -11.0F, 5.0F, 4.0F, 4.0F, 4.0F),
			PartPose.offset(0.0F, -10.0F, -8.0F));

		horns.addOrReplaceChild("real_head", CubeListBuilder.create()
				.texOffs(74, 70)
				.addBox(-6.0F, -2.0F, -13.0F, 12.0F, 8.0F, 15.0F)
				.texOffs(42, 71)
				.addBox(-6.0F, -5.0F, -9.0F, 12.0F, 3.0F, 11.0F),
			PartPose.offsetAndRotation(0.0F, -4.0F, 3.0F, 0.4363323129985824F, 0.0F, 0.0F));

		partdefinition.addOrReplaceChild("body", CubeListBuilder.create(), PartPose.ZERO);

		partdefinition.addOrReplaceChild("front_torso", CubeListBuilder.create()
				.texOffs(0, 0)
				.addBox(-8.0F, -7.0F, -6.0F, 16.0F, 14.0F, 16.0F),
			PartPose.offset(0.0F, 0.0F, 0.0F));

		partdefinition.addOrReplaceChild("neck", CubeListBuilder.create()
				.texOffs(84, 93)
				.addBox(-5.0F, -11.0F, -2.0F, 10.0F, 12.0F, 12.0F),
			PartPose.offsetAndRotation(0.0F, 2.0F, -3.0F, 0.6108652381980153F, 0.0F, 0.0F));

		partdefinition.addOrReplaceChild("back_torso", CubeListBuilder.create()
				.texOffs(0, 30)
				.addBox(-8.0F, -7.0F, 8.0F, 16.0F, 14.0F, 16.0F),
			PartPose.offset(0.0F, 0.0F, 6.0F));

		partdefinition.addOrReplaceChild("right_front_leg", CubeListBuilder.create()
				.texOffs(0, 60)
				.addBox(-3.0F, 2.0F, -3.0F, 6.0F, 16.0F, 6.0F)
				.texOffs(54, 20)
				.addBox(-4.0F, -4.0F, -5.0F, 8.0F, 10.0F, 10.0F),
			PartPose.offset(-5.0F, 6.0F, 0.0F));

		partdefinition.addOrReplaceChild("left_front_leg", CubeListBuilder.create()
				.texOffs(24, 60)
				.addBox(-3.0F, 2.0F, -3.0F, 6.0F, 16.0F, 6.0F)
				.texOffs(90, 20)
				.addBox(-4.0F, -4.0F, -5.0F, 8.0F, 10.0F, 10.0F),
			PartPose.offset(5.0F, 6.0F, 0.0F));

		partdefinition.addOrReplaceChild("right_back_leg", CubeListBuilder.create()
				.texOffs(0, 82)
				.addBox(7.0F, 2.0F, -5.0F, 6.0F, 16.0F, 6.0F)
				.texOffs(54, 50)
				.addBox(6.0F, -4.0F, -7.0F, 8.0F, 10.0F, 10.0F),
			PartPose.offset(-16.0F, 6.0F, 0.0F));

		partdefinition.addOrReplaceChild("left_back_leg", CubeListBuilder.create()
				.texOffs(24, 82)
				.addBox(-13.0F, 2.0F, -5.0F, 6.0F, 16.0F, 6.0F)
				.texOffs(90, 50)
				.addBox(-14.0F, -4.0F, -7.0F, 8.0F, 10.0F, 10.0F),
			PartPose.offset(16.0F, 6.0F, 0.0F));

		for (int i = 0; i < 16; i++) {
			partdefinition.addOrReplaceChild("segment" + i, CubeListBuilder.create()
					.texOffs(0, 112)
					.addBox(-8.0F, -7.0F, 8.0F, 16.0F, 14.0F, 2.0F),
				PartPose.offset(0.0F, 0.0F, 10.0F));
		}

		return LayerDefinition.create(meshdefinition, 128, 128);
	}

	//the rotation of the original head prevents me from making a proper trophy so it needs its own model
	private static LayerDefinition createJappaTrophy() {
		MeshDefinition meshdefinition = new MeshDefinition();
		PartDefinition partdefinition = meshdefinition.getRoot();

		var head = partdefinition.addOrReplaceChild("head",
			CubeListBuilder.create()
				.texOffs(74, 70)
				.addBox(-6.0F, -4.0F, -10.0F, 12.0F, 8.0F, 15.0F)
				.texOffs(42, 71)
				.addBox(-6.0F, -7.0F, -6.0F, 12.0F, 3.0F, 11.0F),
			PartPose.offset(0.0F, -4.0F, 0.0F));

		head.addOrReplaceChild("horns",
			CubeListBuilder.create()
				.texOffs(64, 0)
				.addBox(-9.0F, -6.0F, -1.0F, 4.0F, 10.0F, 10.0F)
				.texOffs(48, 0)
				.addBox(-13.0F, -6.0F, 5.0F, 4.0F, 4.0F, 4.0F)
				.texOffs(92, 0)
				.addBox(5.0F, -6.0F, -1.0F, 4.0F, 10.0F, 10.0F)
				.texOffs(110, 0)
				.addBox(9.0F, -6.0F, 5.0F, 4.0F, 4.0F, 4.0F),
			PartPose.offsetAndRotation(0.0F, -4.0F, 0.0F, -0.4363323129985824F, 0.0F, 0.0F));

		return LayerDefinition.create(meshdefinition, 128, 128);
	}

	private static String getSegmentName(int num) {
		return "segment" + num;
	}

	@Override
	public ModelPart root() {
		return this.root;
	}

	@Override
	public void renderToBuffer(PoseStack stack, VertexConsumer builder, int light, int overlay, int color) {
		super.renderToBuffer(stack, builder, light, overlay, color);

		for (int i = 0; i < 16; i++) {
			final int dyeRgb = Sheep.getColor(DyeColor.byId(i));
			segments[i].render(stack, builder, light, overlay, dyeRgb);
		}
	}

	@Override
	public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
		this.head.xRot = headPitch * Mth.DEG_TO_RAD;
		this.head.yRot = netHeadYaw * Mth.DEG_TO_RAD;

		if (!JappaPackReloadListener.INSTANCE.isJappaPackLoaded()) {
			this.neck.yRot = this.head.yRot;
		}

		this.leftFrontLeg.xRot = Mth.cos(limbSwing * 0.6662F) * 1.4F * limbSwingAmount * 0.5F;
		this.rightFrontLeg.xRot = Mth.cos(limbSwing * 0.6662F + Mth.PI) * 1.4F * limbSwingAmount * 0.5F;
		this.leftBackLeg.xRot = Mth.cos(limbSwing * 0.6662F + Mth.PI) * 1.4F * limbSwingAmount * 0.5F;
		this.rightBackLeg.xRot = Mth.cos(limbSwing * 0.6662F) * 1.4F * limbSwingAmount * 0.5F;
	}

	@Override
	public void prepareMobModel(T entity, float limbSwing, float limbSwingAmount, float partialTicks) {

		// how many colors should we display?
		int count = entity.countColorsSet();
		boolean jappa = JappaPackReloadListener.INSTANCE.isJappaPackLoaded();

		this.head.z = -count - (jappa ? 20 : 11);
		this.neck.z = -count - (jappa ? 17 : 11);
		this.frontTorso.z = -count - (jappa ? 12 : 0);
		this.backTorso.z = count - (jappa ? 10 : 0);
		this.leftBackLeg.z = 9 + count;
		this.rightBackLeg.z = 9 + count;
		this.leftFrontLeg.z = -11 - count;
		this.rightFrontLeg.z = -11 - count;

		// set up the colors displayed in color order
		int segmentOffset = 0;
		for (int color : this.colorOrder) {
			if (entity.isColorPresent(DyeColor.byId(color))) {
				this.segments[color].visible = true;
				this.segments[color].z = segmentOffset - count - (jappa ? 10 : 0);

				segmentOffset += 2;
			} else {
				this.segments[color].visible = false;
			}
		}
	}

	@Override
	public void setupRotationsForTrophy(float x, float y, float z, float mouthAngle) {
		this.head.yRot = y * Mth.DEG_TO_RAD;
		this.head.xRot = z * Mth.DEG_TO_RAD;
	}

	@Override
	public void renderTrophy(PoseStack stack, MultiBufferSource buffer, int light, int overlay, int color, ItemDisplayContext context) {
		stack.scale(0.67F, 0.67F, 0.67F);
		if (!JappaPackReloadListener.INSTANCE.isJappaPackLoaded()) {
			stack.translate(0.0F, 0.5F, context != ItemDisplayContext.NONE ? 0.5F : 0.67F);
		}

		VertexConsumer consumer = buffer.getBuffer(RenderType.entityCutoutNoCull(QuestRamRenderer.TEXTURE));
		this.head.render(stack, consumer, light, overlay, color);
		stack.pushPose();
		stack.scale(1.025F, 1.025F, 1.025F);
		consumer = buffer.getBuffer(RenderType.entityTranslucent(QuestRamRenderer.LINE_TEXTURE));
		this.head.render(stack, consumer, 0xF000F0, overlay, color);
		stack.popPose();
	}
}
