package refinedstorage.tile.data;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.Container;
import net.minecraft.network.datasync.DataSerializer;
import net.minecraft.tileentity.TileEntity;
import refinedstorage.RefinedStorage;
import refinedstorage.container.ContainerBase;
import refinedstorage.network.MessageTileDataParameter;
import refinedstorage.network.MessageTileDataParameterUpdate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TileDataManager {
    private static int PARAMETER_ID = 0;
    private static Map<Integer, TileDataParameter> PARAMETER_MAP = new HashMap<>();

    private List<TileDataParameter> parameters = new ArrayList<>();

    private List<TileDataParameter> watchedParameters = new ArrayList<>();
    private List<Object> watchedParametersCache = new ArrayList<>();

    public static <T> TileDataParameter<T> createParameter(DataSerializer<T> serializer, ITileDataProducer producer) {
        return createParameter(serializer, producer, null);
    }

    public static <T> TileDataParameter<T> createParameter(DataSerializer<T> serializer, ITileDataProducer producer, ITileDataConsumer consumer) {
        return createParameter(serializer, producer, consumer, null);
    }

    public static <T> TileDataParameter<T> createParameter(DataSerializer<T> serializer, ITileDataProducer producer, ITileDataConsumer consumer, ITileDataListener<T> listener) {
        TileDataParameter<T> parameter = new TileDataParameter<>(PARAMETER_ID++, serializer, producer, consumer, listener);

        PARAMETER_MAP.put(parameter.getId(), parameter);

        return parameter;
    }

    public static TileDataParameter getParameter(int id) {
        return PARAMETER_MAP.get(id);
    }

    public static <T> void setParameter(TileDataParameter<T> parameter, T value) {
        RefinedStorage.INSTANCE.network.sendToServer(new MessageTileDataParameterUpdate(parameter, value));
    }

    private TileEntity tile;

    public TileDataManager(TileEntity tile) {
        this.tile = tile;
    }

    public void addParameter(TileDataParameter parameter) {
        parameters.add(parameter);
    }

    public void addWatchedParameter(TileDataParameter parameter) {
        addParameter(parameter);

        watchedParameters.add(parameter);
        watchedParametersCache.add(null);
    }

    public void detectAndSendChanges() {
        for (int i = 0; i < watchedParameters.size(); ++i) {
            TileDataParameter parameter = watchedParameters.get(i);

            Object real = parameter.getValueProducer().getValue(tile);
            Object cached = watchedParametersCache.get(i);

            if (!real.equals(cached)) {
                watchedParametersCache.set(i, real);

                sendParameterToWatchers(parameter);
            }
        }
    }

    public void sendParametersTo(EntityPlayerMP player) {
        for (TileDataParameter parameter : parameters) {
            sendParameter(player, parameter);
        }
    }

    public void sendParameter(EntityPlayerMP player, TileDataParameter parameter) {
        RefinedStorage.INSTANCE.network.sendTo(new MessageTileDataParameter(tile, parameter), player);
    }

    public void sendParameterToWatchers(TileDataParameter parameter) {
        for (EntityPlayer player : tile.getWorld().playerEntities) {
            Container container = player.openContainer;

            if (container instanceof ContainerBase && ((ContainerBase) container).getTile().getPos().equals(tile.getPos())) {
                sendParameter((EntityPlayerMP) player, parameter);
            }
        }
    }
}

@@ -470,16 +470,53 @@
 rUpdate;
+%0Aimport refinedstorage.tile.TileBase;
 %0A%0Aimport
@@ -3591,11 +3591,43 @@
 Base
- &&
+) %7B%0A                TileBase tile =
  ((C
@@ -3660,16 +3660,59 @@
 etTile()
+;%0A%0A                if (tile != null && tile
 .getPos(
@@ -3720,16 +3720,21 @@
 .equals(
+this.
 tile.get
@@ -3739,24 +3739,28 @@
 etPos())) %7B%0A
+    
             
@@ -3806,32 +3806,50 @@
 er, parameter);%0A
+                %7D%0A
             %7D%0A  

Fix NPE with wireless grids