package pneumaticCraft.common.inventory;
import java.lang.reflect.Field;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import org.apache.commons.lang3.ArrayUtils;
import pneumaticCraft.lib.Log;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public abstract class SyncedField<T> {
private final Field field;
private final Object te;
private T lastValue;
private int arrayIndex = -1;
private boolean isLazy;
public SyncedField(Object te, Field field){
this.field = field;
field.setAccessible(true);
this.te = te;
}
public SyncedField setArrayIndex(int arrayIndex){
this.arrayIndex = arrayIndex;
return this;
}
public SyncedField setLazy(boolean lazy){
this.isLazy = lazy;
return this;
}
public boolean update(){
try {
T value = arrayIndex >= 0 ? getValueForArray(field.get(te), arrayIndex) : retrieveValue(field, te);
if(lastValue == null && value != null || lastValue != null && !equals(lastValue, value)) {
lastValue = value == null ? null : copyWhenNecessary(value);
return !isLazy;
}
} catch(Throwable e) {
Log.error("A problem occured when trying to sync the field of " + te.toString() + ". Field: " + field.toString());
e.printStackTrace();
}
return false;
}
protected boolean equals(T oldValue, T newValue){
return oldValue.equals(newValue);
}
protected T copyWhenNecessary(T oldValue){
return oldValue;
}
protected T retrieveValue(Field field, Object te) throws Exception{
return (T)field.get(te);
}
protected void injectValue(Field field, Object te, T value) throws Exception{
field.set(te, value);
}
protected abstract T getValueForArray(Object array, int index);
protected abstract void setValueForArray(Object array, int index, T value) throws Exception;
public T getValue(){
return lastValue;
}
@SideOnly(Side.CLIENT)
public void setValue(T value){
try {
if(arrayIndex >= 0) {
setValueForArray(field.get(te), arrayIndex, value);
} else {
injectValue(field, te, value);
}
} catch(Exception e) {
Log.error("A problem occured when trying to sync the field of " + te.toString() + ". Field: " + field.toString());
e.printStackTrace();
}
}
public static class SyncedInt extends SyncedField<Integer>{
public SyncedInt(Object te, Field field){
super(te, field);
}
@Override
protected Integer getValueForArray(Object array, int index){
return ((int[])array)[index];
}
@Override
protected void setValueForArray(Object array, int index, Integer value) throws Exception{
((int[])array)[index] = value;
}
}
public static class SyncedFloat extends SyncedField<Float>{
public SyncedFloat(Object te, Field field){
super(te, field);
}
@Override
protected Float getValueForArray(Object array, int index){
return ((float[])array)[index];
}
@Override
protected void setValueForArray(Object array, int index, Float value) throws Exception{
((float[])array)[index] = value;
}
}
public static class SyncedDouble extends SyncedField<Double>{
public SyncedDouble(Object te, Field field){
super(te, field);
}
@Override
protected Double getValueForArray(Object array, int index){
return ((double[])array)[index];
}
@Override
protected void setValueForArray(Object array, int index, Double value) throws Exception{
((double[])array)[index] = value;
}
}
public static class SyncedBoolean extends SyncedField<Boolean>{
public SyncedBoolean(Object te, Field field){
super(te, field);
}
@Override
protected Boolean getValueForArray(Object array, int index){
return ((boolean[])array)[index];
}
@Override
protected void setValueForArray(Object array, int index, Boolean value) throws Exception{
((boolean[])array)[index] = value;
}
}
public static class SyncedString extends SyncedField<String>{
public SyncedString(Object te, Field field){
super(te, field);
}
@Override
protected String getValueForArray(Object array, int index){
return ((String[])array)[index];
}
@Override
protected void setValueForArray(Object array, int index, String value) throws Exception{
((String[])array)[index] = value;
}
}
public static class SyncedEnum extends SyncedField<Byte>{
public SyncedEnum(Object te, Field field){
super(te, field);
}
@Override
protected Byte getValueForArray(Object array, int index){
return ((byte[])array)[index];
}
@Override
protected void setValueForArray(Object array, int index, Byte value) throws Exception{
((byte[])array)[index] = value;
}
@Override
protected Byte retrieveValue(Field field, Object te) throws Exception{
Object[] enumTypes = field.getType().getEnumConstants();
return (byte)ArrayUtils.indexOf(enumTypes, field.get(te));
}
@Override
protected void injectValue(Field field, Object te, Byte value) throws Exception{
Object enumType = field.getType().getEnumConstants()[value];
field.set(te, enumType);
}
}
public static class SyncedItemStack extends SyncedField<ItemStack>{
public SyncedItemStack(Object te, Field field){
super(te, field);
}
@Override
protected ItemStack getValueForArray(Object array, int index){
return ((ItemStack[])array)[index];
}
@Override
protected void setValueForArray(Object array, int index, ItemStack value) throws Exception{
((ItemStack[])array)[index] = value;
}
}
public static class SyncedFluidTank extends SyncedField<FluidStack>{
public SyncedFluidTank(Object te, Field field){
super(te, field);
}
@Override
protected FluidStack getValueForArray(Object array, int index){
return ((FluidTank[])array)[index].getFluid();
}
@Override
protected void setValueForArray(Object array, int index, FluidStack value) throws Exception{
((FluidTank[])array)[index].setFluid(value);
}
@Override
protected FluidStack retrieveValue(Field field, Object te) throws Exception{
FluidTank tank = (FluidTank)field.get(te);
return tank.getFluid();
}
@Override
protected void injectValue(Field field, Object te, FluidStack value) throws Exception{
FluidTank tank = (FluidTank)field.get(te);
tank.setFluid(value);
}
@Override
protected boolean equals(FluidStack oldValue, FluidStack newValue){
return oldValue.isFluidEqual(newValue) && oldValue.amount == newValue.amount;
}
@Override
protected FluidStack copyWhenNecessary(FluidStack oldValue){
return oldValue.copy();
}
}
}