package com.wuest.prefab.base;

import com.wuest.prefab.Prefab;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.apache.logging.log4j.Level;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * This is the base tile entity used by the mod.
 *
 * @param <T> The base configuration used by this tile entity.
 * @author WuestMan
 */
public abstract class TileEntityBase<T extends BaseConfig> extends BlockEntity {
	protected T config;

	protected TileEntityBase(BlockEntityType<?> tileEntityTypeIn, BlockPos pos, BlockState state) {
		super(tileEntityTypeIn, pos, state);
	}

	/**
	 * @return Gets the configuration class used by this tile entity.
	 */
	public T getConfig() {
		return this.config;
	}

	/**
	 * Sets the configuration class used by this tile entity.
	 *
	 * @param value The updated tile entity.
	 */
	public void setConfig(T value) {
		this.config = value;
		this.setChanged();

		CompoundTag tileData = this.getTileData();

		if (this.config != null) {
			this.config.WriteToNBTCompound(tileData);
		}
	}

	public Class<T> getTypeParameterClass() {
		Type type = getClass().getGenericSuperclass();
		ParameterizedType paramType = (ParameterizedType) type;
		return (Class<T>) paramType.getActualTypeArguments()[0];
	}

	/**
	 * Allows for a specialized description packet to be created. This is often used
	 * to sync tile entity data from the server to the client easily. For example
	 * this is used by signs to synchronize the text to be displayed.
	 */
	@Override
	public ClientboundBlockEntityDataPacket getUpdatePacket() {
		// Don't send the packet until the position has been set.
		if (this.worldPosition.getX() == 0 && this.worldPosition.getY() == 0 && this.worldPosition.getZ() == 0) {
			return null;
		}

		return ClientboundBlockEntityDataPacket.create(this);
	}

	@Override
	public boolean triggerEvent(int id, int type) {
		return true;
	}

	@Override
	public CompoundTag getUpdateTag() {
		// This is overwritten so our custom save event is done.
		return this.save(new CompoundTag());
	}

	@Override
	public CompoundTag save(CompoundTag compound) {
		CompoundTag tileData = this.getTileData();

		if (this.config != null) {
			this.config.WriteToNBTCompound(tileData);
		}

		compound = super.save(compound);

		return compound;
	}

	@Override
	public void load(CompoundTag compound) {
		super.load(compound);

		this.config = this.createConfigInstance().ReadFromCompoundTag(this.getTileData());
	}

	public T createConfigInstance() {
		try {
			return this.getTypeParameterClass().newInstance();
		} catch (InstantiationException | IllegalAccessException e) {
			Prefab.LOGGER.log(Level.ERROR, e.getMessage());
			e.printStackTrace();
		}

		return null;
	}
}

@@ -425,16 +425,58 @@
 j.Level;
+%0Aimport org.jetbrains.annotations.NotNull;
 %0A%0Aimport
@@ -2242,32 +2242,41 @@
 verride%0A%09public 
+@NotNull 
 CompoundTag getU
@@ -2353,43 +2353,103 @@
 .%0A%09%09
-return this.save(new CompoundTag())
+CompoundTag updateTag = new CompoundTag();%0A%09%09this.saveAdditional(updateTag);%0A%09%09return updateTag
 ;%0A%09%7D
@@ -2473,25 +2473,27 @@
 lic 
-CompoundTag save(
+void load(@NotNull 
 Comp
@@ -2518,58 +2518,33 @@
 %7B%0A%09%09
-CompoundTag tileData = this.getTileData(
+super.load(compound
 );%0A%0A%09%09
-if (
 this
@@ -2555,122 +2555,77 @@
 fig 
-!
 = 
-null) %7B%0A%09%09%09this.config.WriteToNBTCompound(tileData);%0A%09%09%7D%0A%0A%09%09compound = super.save(compound);%0A%0A%09%09return compound
+this.createConfigInstance().ReadFromCompoundTag(this.getTileData())
 ;%0A%09%7D
@@ -2650,21 +2650,40 @@
 ic void 
-load(
+saveAdditional(@NotNull 
 Compound
@@ -2704,33 +2704,58 @@
 %7B%0A%09%09
-super.load(compound
+CompoundTag tileData = this.getTileData(
 );%0A%0A%09%09
+if (
 this
@@ -2766,78 +2766,67 @@
 fig 
+!
 = 
-this.createConfigInstance().ReadFromCompoundTag(this.getT
+null) %7B%0A%09%09%09this.config.WriteToNBTCompound(t
 ileData
-()
 );
+%0A%09%09%7D
 %0A%09%7D%0A

Fix tile entity base after update