package mekanism.api.gas;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import mekanism.api.util.CapabilityUtils;
import mekanism.common.capabilities.Capabilities;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
/**
* A handy class containing several utilities for efficient gas transfer.
* @author AidanBrady
*
*/
public final class GasTransmission
{
public static IGasHandler[] getConnectedAcceptors(TileEntity tileEntity, Collection<EnumFacing> sides)
{
return getConnectedAcceptors(tileEntity.getPos(), tileEntity.getWorld(), sides);
}
public static IGasHandler[] getConnectedAcceptors(BlockPos pos, World world, Collection<EnumFacing> sides)
{
IGasHandler[] acceptors = new IGasHandler[] {null, null, null, null, null, null};
for(EnumFacing orientation : sides)
{
TileEntity acceptor = world.getTileEntity(pos.offset(orientation));
if(CapabilityUtils.hasCapability(acceptor, Capabilities.GAS_HANDLER_CAPABILITY, orientation.getOpposite()))
{
acceptors[orientation.ordinal()] = CapabilityUtils.getCapability(acceptor, Capabilities.GAS_HANDLER_CAPABILITY, orientation.getOpposite());
}
}
return acceptors;
}
/**
* Gets all the acceptors around a tile entity.
* @param tileEntity - center tile entity
* @return array of IGasAcceptors
*/
public static IGasHandler[] getConnectedAcceptors(TileEntity tileEntity)
{
return getConnectedAcceptors(tileEntity.getPos(), tileEntity.getWorld(), Arrays.asList(EnumFacing.VALUES));
}
public static IGasHandler[] getConnectedAcceptors(BlockPos pos, World world)
{
return getConnectedAcceptors(pos, world, Arrays.asList(EnumFacing.VALUES));
}
public static boolean isValidAcceptorOnSide(TileEntity tile, EnumFacing side)
{
if(CapabilityUtils.hasCapability(tile, Capabilities.GRID_TRANSMITTER_CAPABILITY, side.getOpposite()))
{
return false;
}
if(CapabilityUtils.hasCapability(tile, Capabilities.TUBE_CONNECTION_CAPABILITY, side.getOpposite()))
{
ITubeConnection connection = CapabilityUtils.getCapability(tile, Capabilities.TUBE_CONNECTION_CAPABILITY, side.getOpposite());
if(connection.canTubeConnect(side.getOpposite()))
{
return true;
}
}
return false;
}
/**
* Removes a specified amount of gas from an IGasItem.
* @param itemStack - ItemStack of the IGasItem
* @param type - type of gas to remove from the IGasItem, null if it doesn't matter
* @param amount - amount of gas to remove from the ItemStack
* @return the GasStack removed by the IGasItem
*/
public static GasStack removeGas(ItemStack itemStack, Gas type, int amount)
{
if(itemStack != null && itemStack.getItem() instanceof IGasItem)
{
IGasItem item = (IGasItem)itemStack.getItem();
if(type != null && item.getGas(itemStack) != null && item.getGas(itemStack).getGas() != type || !item.canProvideGas(itemStack, type))
{
return null;
}
return item.removeGas(itemStack, amount);
}
return null;
}
/**
* Adds a specified amount of gas to an IGasItem.
* @param itemStack - ItemStack of the IGasItem
* @param stack - stack to add to the IGasItem
* @return amount of gas accepted by the IGasItem
*/
public static int addGas(ItemStack itemStack, GasStack stack)
{
if(itemStack != null && itemStack.getItem() instanceof IGasItem && ((IGasItem)itemStack.getItem()).canReceiveGas(itemStack, stack.getGas()))
{
return ((IGasItem)itemStack.getItem()).addGas(itemStack, stack.copy());
}
return 0;
}
/**
* Emits gas from a central block by splitting the received stack among the sides given.
* @param stack - the stack to output
* @param from - the TileEntity to output from
* @param sides - the list of sides to output from
* @return the amount of gas emitted
*/
public static int emit(GasStack stack, TileEntity from, Collection<EnumFacing> sides)
{
if(stack == null)
{
return 0;
}
List<IGasHandler> availableAcceptors = new ArrayList<IGasHandler>();
IGasHandler[] possibleAcceptors = getConnectedAcceptors(from, sides);
for(int i = 0; i < possibleAcceptors.length; i++)
{
IGasHandler handler = possibleAcceptors[i];
if(handler != null && handler.canReceiveGas(EnumFacing.getFront(i).getOpposite(), stack.getGas()))
{
availableAcceptors.add(handler);
}
}
Collections.shuffle(availableAcceptors);
int toSend = stack.amount;
int prevSending = toSend;
if(!availableAcceptors.isEmpty())
{
int divider = availableAcceptors.size();
int remaining = toSend % divider;
int sending = (toSend-remaining)/divider;
for(IGasHandler acceptor : availableAcceptors)
{
int currentSending = sending;
if(remaining > 0)
{
currentSending++;
remaining--;
}
EnumFacing dir = EnumFacing.getFront(Arrays.asList(possibleAcceptors).indexOf(acceptor)).getOpposite();
toSend -= acceptor.receiveGas(dir, new GasStack(stack.getGas(), currentSending), true);
}
}
return prevSending-toSend;
}
}