// Path: src/main/java/org/cyclops/integratedtunnels/api/network/IFluidNetwork.java
// public interface IFluidNetwork extends IPositionedAddonsNetworkIngredients<FluidStack, Integer> {
// 
// }
// 
// Path: src/main/java/org/cyclops/integratedtunnels/capability/network/FluidNetworkConfig.java
// public class FluidNetworkConfig extends CapabilityConfig<IFluidNetwork> {
// 
//     @CapabilityInject(IFluidNetwork.class)
//     public static Capability<IFluidNetwork> CAPABILITY = null;
// 
//     public FluidNetworkConfig() {
//         super(
//                 CommonCapabilities._instance,
//                 "fluidNetwork",
//                 IFluidNetwork.class,
//                 new DefaultCapabilityStorage<IFluidNetwork>(),
//                 () -> new FluidNetwork(null)
//         );
//     }
// 
// }
// 
// Path: src/main/java/org/cyclops/integratedtunnels/core/part/PartStateRoundRobin.java
// public class PartStateRoundRobin<P extends IPartTypeWriter> extends PartStateWriterBase<P> {
// 
//     private IPartPosIteratorHandler partPosIteratorHandler = null;
// 
//     public PartStateRoundRobin(int inventorySize) {
//         super(inventorySize);
//     }
// 
//     public void setPartPosIteratorHandler(IPartPosIteratorHandler partPosIteratorHandler) {
//         this.partPosIteratorHandler = partPosIteratorHandler;
//     }
// 
//     public IPartPosIteratorHandler getPartPosIteratorHandler() {
//         return partPosIteratorHandler;
//     }
// }
// 
// Path: src/main/java/org/cyclops/integratedtunnels/core/predicate/IngredientPredicate.java
// public abstract class IngredientPredicate<T, M> implements Predicate<T>, ITunnelTransfer {
// 
//     private final IngredientComponent<T, M> ingredientComponent;
//     private final T instance;
//     private final M matchFlags;
//     private final boolean blacklist;
//     private final boolean empty;
//     private final int maxQuantity;
//     private final boolean exactQuantity;
// 
//     public IngredientPredicate(IngredientComponent<T, M> ingredientComponent,
//                                T instance, M matchFlags, boolean blacklist, boolean empty,
//                                int maxQuantity, boolean exactQuantity) {
//         this.ingredientComponent = ingredientComponent;
//         this.instance = instance;
//         this.matchFlags = matchFlags;
//         this.blacklist = blacklist;
//         this.empty = empty;
//         this.maxQuantity = maxQuantity;
//         this.exactQuantity = exactQuantity;
//     }
// 
//     // Note: implementors of this method *should* override equals and hashcode.
//     public IngredientPredicate(IngredientComponent<T, M> ingredientComponent,
//                                boolean blacklist, boolean empty, int maxQuantity, boolean exactQuantity) {
//         this(ingredientComponent, ingredientComponent.getMatcher().getEmptyInstance(), null,
//                 blacklist, empty, maxQuantity, exactQuantity);
//     }
// 
//     public IngredientComponent<T, M> getIngredientComponent() {
//         return ingredientComponent;
//     }
// 
//     @Nonnull
//     public T getInstance() {
//         return instance;
//     }
// 
//     public M getMatchFlags() {
//         return matchFlags;
//     }
// 
//     public boolean hasMatchFlags() {
//         return matchFlags != null && !blacklist;
//     }
// 
//     public boolean isBlacklist() {
//         return blacklist;
//     }
// 
//     public boolean isEmpty() {
//         return empty;
//     }
// 
//     public int getMaxQuantity() {
//         return maxQuantity;
//     }
// 
//     public boolean isExactQuantity() {
//         return exactQuantity;
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         if (!(obj instanceof IngredientPredicate)) {
//             return false;
//         }
//         IngredientPredicate that = (IngredientPredicate) obj;
//         return this.ingredientComponent == that.ingredientComponent
//                 && this.ingredientComponent.getMatcher().matchesExactly(this.instance, (T) that.instance)
//                 && Objects.equals(this.matchFlags, that.matchFlags)
//                 && this.blacklist == that.blacklist
//                 && this.empty == that.empty
//                 && this.maxQuantity == that.maxQuantity
//                 && this.exactQuantity == that.exactQuantity;
//     }
// 
//     @Override
//     public int hashCode() {
//         return ingredientComponent.hashCode()
//                 ^ ingredientComponent.getMatcher().hash(instance)
//                 ^ Objects.hashCode(matchFlags)
//                 ^ (blacklist ? 1 : 0)
//                 ^ (empty ? 2 : 4)
//                 ^ maxQuantity
//                 ^ (exactQuantity ? 8 : 16);
//     }
// 
//     public static enum EmptyBehaviour {
//         ANY,
//         NONE;
// 
//         public static EmptyBehaviour fromBoolean(boolean emptyIsAny) {
//             return emptyIsAny ? ANY : NONE;
//         }
//     }
// }


import net.minecraftforge.fluids.FluidStack;
import org.cyclops.commoncapabilities.api.ingredient.storage.IIngredientComponentStorage;
import org.cyclops.integrateddynamics.api.network.INetwork;
import org.cyclops.integrateddynamics.api.part.PartTarget;
import org.cyclops.integrateddynamics.api.part.aspect.property.IAspectProperties;
import org.cyclops.integratedtunnels.api.network.IFluidNetwork;
import org.cyclops.integratedtunnels.capability.network.FluidNetworkConfig;
import org.cyclops.integratedtunnels.core.part.PartStateRoundRobin;
import org.cyclops.integratedtunnels.core.predicate.IngredientPredicate;
import javax.annotation.Nullable;
package org.cyclops.integratedtunnels.part.aspect;



/**
 * @author rubensworks
 */
public class FluidTargetStorage extends ChanneledTarget<IFluidNetwork, FluidStack> implements IFluidTarget {

    private final ITunnelConnection connection;
    private final IIngredientComponentStorage<FluidStack, Integer> storage;
    private final IngredientPredicate<FluidStack, Integer> fluidStackMatcher;
    private final PartTarget partTarget;
    private final IAspectProperties properties;

    public FluidTargetStorage(ITunnelTransfer transfer, INetwork network,
                              IIngredientComponentStorage<FluidStack, Integer> storage,
                              IngredientPredicate<FluidStack, Integer> fluidStackMatcher, PartTarget partTarget,
                              IAspectProperties properties, @Nullable PartStateRoundRobin<?> partState) {
        super(network, network.getCapability(FluidNetworkConfig.CAPABILITY).orElse(null), partState,
                properties.getValue(TunnelAspectWriteBuilders.PROP_CHANNEL).getRawValue(),
// Path: src/main/java/org/cyclops/integratedtunnels/api/network/IFluidNetwork.java
// public interface IFluidNetwork extends IPositionedAddonsNetworkIngredients<FluidStack, Integer> {
// 
// }
// 
// Path: src/main/java/org/cyclops/integratedtunnels/capability/network/FluidNetworkConfig.java
// public class FluidNetworkConfig extends CapabilityConfig<IFluidNetwork> {
// 
//     @CapabilityInject(IFluidNetwork.class)
//     public static Capability<IFluidNetwork> CAPABILITY = null;
// 
//     public FluidNetworkConfig() {
//         super(
//                 CommonCapabilities._instance,
//                 "fluidNetwork",
//                 IFluidNetwork.class,
//                 new DefaultCapabilityStorage<IFluidNetwork>(),
//                 () -> new FluidNetwork(null)
//         );
//     }
// 
// }
// 
// Path: src/main/java/org/cyclops/integratedtunnels/core/part/PartStateRoundRobin.java
// public class PartStateRoundRobin<P extends IPartTypeWriter> extends PartStateWriterBase<P> {
// 
//     private IPartPosIteratorHandler partPosIteratorHandler = null;
// 
//     public PartStateRoundRobin(int inventorySize) {
//         super(inventorySize);
//     }
// 
//     public void setPartPosIteratorHandler(IPartPosIteratorHandler partPosIteratorHandler) {
//         this.partPosIteratorHandler = partPosIteratorHandler;
//     }
// 
//     public IPartPosIteratorHandler getPartPosIteratorHandler() {
//         return partPosIteratorHandler;
//     }
// }
// 
// Path: src/main/java/org/cyclops/integratedtunnels/core/predicate/IngredientPredicate.java
// public abstract class IngredientPredicate<T, M> implements Predicate<T>, ITunnelTransfer {
// 
//     private final IngredientComponent<T, M> ingredientComponent;
//     private final T instance;
//     private final M matchFlags;
//     private final boolean blacklist;
//     private final boolean empty;
//     private final int maxQuantity;
//     private final boolean exactQuantity;
// 
//     public IngredientPredicate(IngredientComponent<T, M> ingredientComponent,
//                                T instance, M matchFlags, boolean blacklist, boolean empty,
//                                int maxQuantity, boolean exactQuantity) {
//         this.ingredientComponent = ingredientComponent;
//         this.instance = instance;
//         this.matchFlags = matchFlags;
//         this.blacklist = blacklist;
//         this.empty = empty;
//         this.maxQuantity = maxQuantity;
//         this.exactQuantity = exactQuantity;
//     }
// 
//     // Note: implementors of this method *should* override equals and hashcode.
//     public IngredientPredicate(IngredientComponent<T, M> ingredientComponent,
//                                boolean blacklist, boolean empty, int maxQuantity, boolean exactQuantity) {
//         this(ingredientComponent, ingredientComponent.getMatcher().getEmptyInstance(), null,
//                 blacklist, empty, maxQuantity, exactQuantity);
//     }
// 
//     public IngredientComponent<T, M> getIngredientComponent() {
//         return ingredientComponent;
//     }
// 
//     @Nonnull
//     public T getInstance() {
//         return instance;
//     }
// 
//     public M getMatchFlags() {
//         return matchFlags;
//     }
// 
//     public boolean hasMatchFlags() {
//         return matchFlags != null && !blacklist;
//     }
// 
//     public boolean isBlacklist() {
//         return blacklist;
//     }
// 
//     public boolean isEmpty() {
//         return empty;
//     }
// 
//     public int getMaxQuantity() {
//         return maxQuantity;
//     }
// 
//     public boolean isExactQuantity() {
//         return exactQuantity;
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         if (!(obj instanceof IngredientPredicate)) {
//             return false;
//         }
//         IngredientPredicate that = (IngredientPredicate) obj;
//         return this.ingredientComponent == that.ingredientComponent
//                 && this.ingredientComponent.getMatcher().matchesExactly(this.instance, (T) that.instance)
//                 && Objects.equals(this.matchFlags, that.matchFlags)
//                 && this.blacklist == that.blacklist
//                 && this.empty == that.empty
//                 && this.maxQuantity == that.maxQuantity
//                 && this.exactQuantity == that.exactQuantity;
//     }
// 
//     @Override
//     public int hashCode() {
//         return ingredientComponent.hashCode()
//                 ^ ingredientComponent.getMatcher().hash(instance)
//                 ^ Objects.hashCode(matchFlags)
//                 ^ (blacklist ? 1 : 0)
//                 ^ (empty ? 2 : 4)
//                 ^ maxQuantity
//                 ^ (exactQuantity ? 8 : 16);
//     }
// 
//     public static enum EmptyBehaviour {
//         ANY,
//         NONE;
// 
//         public static EmptyBehaviour fromBoolean(boolean emptyIsAny) {
//             return emptyIsAny ? ANY : NONE;
//         }
//     }
// }


// Path: src/main/java/org/cyclops/integratedtunnels/part/aspect/FluidTargetStorage.java
import net.minecraftforge.fluids.FluidStack;
import org.cyclops.commoncapabilities.api.ingredient.storage.IIngredientComponentStorage;
import org.cyclops.integrateddynamics.api.network.INetwork;
import org.cyclops.integrateddynamics.api.part.PartTarget;
import org.cyclops.integrateddynamics.api.part.aspect.property.IAspectProperties;
import org.cyclops.integratedtunnels.api.network.IFluidNetwork;
import org.cyclops.integratedtunnels.capability.network.FluidNetworkConfig;
import org.cyclops.integratedtunnels.core.part.PartStateRoundRobin;
import org.cyclops.integratedtunnels.core.predicate.IngredientPredicate;
import javax.annotation.Nullable;

package org.cyclops.integratedtunnels.part.aspect;



/**
 * @author rubensworks
 */
public class FluidTargetStorage extends ChanneledTarget<IFluidNetwork, FluidStack> implements IFluidTarget {

    private final ITunnelConnection connection;
    private final IIngredientComponentStorage<FluidStack, Integer> storage;
    private final IngredientPredicate<FluidStack, Integer> fluidStackMatcher;
    private final PartTarget partTarget;
    private final IAspectProperties properties;

    public FluidTargetStorage(ITunnelTransfer transfer, INetwork network,
                              IIngredientComponentStorage<FluidStack, Integer> storage,
                              IngredientPredicate<FluidStack, Integer> fluidStackMatcher, PartTarget partTarget,
                              IAspectProperties properties, @Nullable PartStateRoundRobin<?> partState) {
        super(network, network.getCapability(FluidNetworkConfig.CAPABILITY).orElse(null), partState,
                properties.getValue(TunnelAspectWriteBuilders.PROP_CHANNEL).getRawValue(),
                properties.getValue(TunnelAspectWriteBuilders.PROP_ROUNDROBIN).getRawValue(),