package mekanism.api.gas;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import mekanism.api.Coord4D;
import mekanism.api.transmitters.ITransmitterTile;
import mekanism.api.transmitters.TransmissionType;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
/**
* A handy class containing several utilities for efficient gas transfer.
* @author AidanBrady
*
*/
public final class GasTransmission
{
/**
* Gets all the acceptors around a tile entity.
* @param tileEntity - center tile entity
* @return array of IGasAcceptors
*/
public static IGasHandler[] getConnectedAcceptors(TileEntity tileEntity)
{
IGasHandler[] acceptors = new IGasHandler[] {null, null, null, null, null, null};
for(ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS)
{
TileEntity acceptor = Coord4D.get(tileEntity).getFromSide(orientation).getTileEntity(tileEntity.getWorldObj());
if(acceptor instanceof IGasHandler)
{
acceptors[orientation.ordinal()] = (IGasHandler)acceptor;
}
}
return acceptors;
}
/**
* Gets all the tube connections around a tile entity.
* @param tileEntity - center tile entity
* @return array of ITubeConnections
*/
public static ITubeConnection[] getConnections(TileEntity tileEntity)
{
ITubeConnection[] connections = new ITubeConnection[] {null, null, null, null, null, null};
for(ForgeDirection orientation : ForgeDirection.VALID_DIRECTIONS)
{
TileEntity connection = Coord4D.get(tileEntity).getFromSide(orientation).getTileEntity(tileEntity.getWorldObj());
if(canConnect(connection, orientation))
{
connections[orientation.ordinal()] = (ITubeConnection)connection;
}
}
return connections;
}
/**
* Whether or not a TileEntity can connect to a specified tile on a specified side.
* @param tileEntity - TileEntity to attempt connection to
* @param side - side to attempt connection on
* @return if this tile and side are connectable
*/
public static boolean canConnect(TileEntity tileEntity, ForgeDirection side)
{
if(tileEntity instanceof ITubeConnection && (!(tileEntity instanceof ITransmitterTile) || TransmissionType.checkTransmissionType(((ITransmitterTile)tileEntity).getTransmitter(), TransmissionType.GAS)))
{
if(((ITubeConnection)tileEntity).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 sides - the list of sides to output from
* @param stack - the stack to output
* @param from - the TileEntity to output from
* @return the amount of gas emitted
*/
public static int emit(List<ForgeDirection> sides, GasStack stack, TileEntity from)
{
if(stack == null)
{
return 0;
}
List<IGasHandler> availableAcceptors = new ArrayList<IGasHandler>();
IGasHandler[] possibleAcceptors = getConnectedAcceptors(from);
for(int i = 0; i < possibleAcceptors.length; i++)
{
IGasHandler handler = possibleAcceptors[i];
if(handler != null && handler.canReceiveGas(ForgeDirection.getOrientation(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--;
}
ForgeDirection dir = ForgeDirection.getOrientation(Arrays.asList(possibleAcceptors).indexOf(acceptor)).getOpposite();
toSend -= acceptor.receiveGas(dir, new GasStack(stack.getGas(), currentSending), true);
}
}
return prevSending-toSend;
}
}