package mimickal.mc.floodgate;

import com.enderio.core.common.fluid.IFluidWrapper;
import net.minecraft.block.Block;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;

public class TileEntityFloodgate extends TileEntity implements IFluidWrapper {

    public static final int MAX_CAPACITY = Fluid.BUCKET_VOLUME;

    private FluidStack heldFluid;

    /*-----------------------------------------------------------------------*
     * IFluidWrapper impl
     *-----------------------------------------------------------------------*/

    /**
     * This is called prior to moving any fluid. I assume this is used to
     * determine how much of a fluid the floodgate should be allowed to
     * accept (if any).
     *
     * @param resource The fluid being offered to the floodgate
     * @return How much of the fluid the floodgate can accept (maybe?)
     */
    @Override
    public int offer(FluidStack resource) {
        // TODO eventually make sure this fluid is usable (i.e. does it have source blocks we can place?)
        return MAX_CAPACITY;
    }

    /**
     * This is what the floodgate does when the offered fluid is actually
     * consumed.
     *
     * @param fluid The fluid filling the floodgate
     * @return The amount of fluid the floodgate accepted
     */
    @Override
    public int fill(FluidStack fluid) {
        int amountFilled = Math.min(fluid.amount, MAX_CAPACITY);
        // TODO check that we have enough fluid to place a source block
        heldFluid = new FluidStack(fluid, amountFilled);

        BlockPos placeAt = findNearestFreeSpot();

        if (placeAt == null) {
            return 0; // Don't actually consume fluid if we can't find a place to put it
        } else {
            placeFluid(fluid, placeAt);
            return amountFilled;
        }
    }

    /**
     * The draining version of "offer". Pipes use this function to figure out
     * if they can extract any fluid from the floodgate.
     *
     * The floodgate drains itself by placing fluid into the world,
     * therefore it never has any fluid available for draining.
     *
     * @return null
     */
    @Nullable
    @Override
    public FluidStack getAvailableFluid() {
        return null;
    }

    /**
     * This function contains the logic for how a floodgate responds to having
     * fluid extracted from it.
     * The floodgate should never have fluid extracted from it.
     *
     * @param resource Unused. Not sure what this is for.
     * @return null
     */
    @Nullable
    @Override
    public FluidStack drain(FluidStack resource) {
        return null;
    }

    /**
     * FIXME figure out what this actually does
     * Seriously I have no idea.
     * @return
     */
    @Nonnull
    @Override
    public List<ITankInfoWrapper> getTankInfoWrappers() {
        return new ArrayList<>();
    }

    /*-----------------------------------------------------------------------*
     * Fluid placing logic
     *-----------------------------------------------------------------------*/

    private void placeFluid(FluidStack fluid, BlockPos placeAt) {
        Block fluidSourceBlock = fluid.getFluid().getBlock();
        this.worldObj.setBlockState(placeAt, fluidSourceBlock.getDefaultState());
    }

    @Nullable
    private BlockPos findNearestFreeSpot() {
        BlockPos testPos = this.pos.down();

        if (this.worldObj.isAirBlock(testPos)) {
            return testPos;
        } else {
            return null;
        }
        //this.worldObj.getBlockState(testPos).getBlock().
    }

}

@@ -1415,17 +1415,25 @@
  @param 
-f
+incomingF
 luid The
@@ -1568,25 +1568,33 @@
 (FluidStack 
-f
+incomingF
 luid) %7B%0A    
@@ -1617,129 +1617,191 @@
 lled
- = Math.min(fluid.amount, MAX_CAPACITY);%0A        // TODO check that we have enough fluid to place a source block%0A
+;%0A%0A        // Attempt to consume enough fluid to hit MAX_CAPACITY%0A        if (heldFluid == null) %7B%0A            amountFilled = Math.min(incomingFluid.amount, MAX_CAPACITY);%0A   
         
 held
@@ -1796,16 +1796,17 @@
         
+ 
 heldFlui
@@ -1824,17 +1824,25 @@
 idStack(
-f
+incomingF
 luid, am
@@ -1858,194 +1858,480 @@
 d);%0A
-%0A        BlockPos placeAt = findNearestFreeSpot();%0A%0A        if (placeAt == null) %7B%0A            return 0; // Don't actually consume fluid if we can't find a place to put it%0A        %7D else
+        %7D%0A        else %7B%0A            if (heldFluid.amount + incomingFluid.amount %3E= MAX_CAPACITY) %7B%0A                amountFilled = MAX_CAPACITY - heldFluid.amount;%0A            %7D else %7B%0A                amountFilled = incomingFluid.amount;%0A            %7D%0A%0A            heldFluid = new FluidStack(incomingFluid, heldFluid.amount + amountFilled);%0A        %7D%0A%0A        // When we have a full tank, attempt to place a fluid source block%0A        if (heldFluid.amount == MAX_CAPACITY)
  %7B%0A 
@@ -2350,35 +2350,32 @@
 lace
+Held
 Fluid(
-fluid, placeAt
 );%0A    
+    %7D%0A%0A
     
@@ -2399,26 +2399,16 @@
 Filled;%0A
-        %7D%0A
     %7D%0A%0A 
@@ -3657,52 +3657,178 @@
 lace
+Held
 Fluid(
-FluidStack fluid, BlockPos placeAt) %7B%0A
+) %7B%0A        BlockPos nearestFreeSpot = findNearestFreeSpot();%0A%0A        if (nearestFreeSpot != null) %7B%0A            // Fill free spot with fluid source block%0A    
     
@@ -3856,17 +3856,21 @@
 Block = 
-f
+heldF
 luid.get
@@ -3885,24 +3885,28 @@
 getBlock();%0A
+    
         this
@@ -3933,14 +3933,22 @@
 ate(
-placeA
+nearestFreeSpo
 t, f
@@ -3982,16 +3982,89 @@
 tate());
+%0A%0A            // %22Empty%22 the tank%0A            heldFluid = null;%0A        %7D
 %0A    %7D%0A%0A

Add ability to consume and hold partial fluid buckets