package crazypants.enderio.machine.vat;
import static crazypants.util.EE3Util.registerRecipe;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import org.apache.commons.lang3.NotImplementedException;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import crazypants.enderio.Log;
import crazypants.enderio.machine.MachineRecipeInput;
import crazypants.enderio.machine.recipe.IRecipe;
import crazypants.enderio.machine.recipe.RecipeBonusType;
import crazypants.enderio.machine.recipe.RecipeInput;
import crazypants.enderio.machine.recipe.RecipeOutput;
import crazypants.util.EE3Util;
public class VatRecipe implements IRecipe {
protected final List<ItemStack> inputStacks;
protected final boolean valid;
protected final Table<RecipeInput, RecipeInput, FluidStack> inputFluidStacks = HashBasedTable.create();
protected final Table<RecipeInput, RecipeInput, FluidStack> outputFluidStacks = HashBasedTable.create();
protected final RecipeInput[] inputs;
protected final RecipeOutput[] output;
protected final int energyRequired;
private int requiredItems;
public VatRecipe(IRecipe recipe) {
FluidStack inputFluidStack = null, outputFluidStack = null;
inputs = recipe.getInputs();
for (RecipeOutput output : recipe.getOutputs()) {
if(output.isFluid()) {
outputFluidStack = output.getFluidOutput().copy();
break;
}
}
if (outputFluidStack == null) {
Log.warn("Ignoring invalid VAT recipe without output fluid");
} else {
requiredItems = 1;
for (RecipeInput ri : inputs) {
if (!ri.isFluid() && ri.getSlotNumber() == 1) {
requiredItems = 2;
}
}
if (requiredItems == 2) {
for (RecipeInput r0 : inputs) {
if (!r0.isFluid() && r0.getSlotNumber() == 0) {
for (RecipeInput r1 : inputs) {
if (!r1.isFluid() && r1.getSlotNumber() == 1) {
for (RecipeInput r2 : inputs) {
if (r2.isFluid()) {
float im = r0.getMulitplier() * r1.getMulitplier();
inputFluidStack = r2.getFluidInput().copy();
inputFluidStack.amount = Math.round(FluidContainerRegistry.BUCKET_VOLUME * im);
outputFluidStack.amount = Math.round(im * r2.getMulitplier() * FluidContainerRegistry.BUCKET_VOLUME);
inputFluidStacks.put(r0, r1, inputFluidStack.copy());
outputFluidStacks.put(r0, r1, outputFluidStack.copy());
registerRecipe(outputFluidStack.copy(), r0.getInput().copy(), r1.getInput().copy(), inputFluidStack.copy());
}
}
}
}
}
}
} else {
for (RecipeInput r0 : inputs) {
if (!r0.isFluid()) {
for (RecipeInput r2 : inputs) {
if (r2.isFluid()) {
float im = r0.getMulitplier();
inputFluidStack = r2.getFluidInput().copy();
inputFluidStack.amount = Math.round(FluidContainerRegistry.BUCKET_VOLUME * im);
outputFluidStack.amount = Math.round(im * r2.getMulitplier() * FluidContainerRegistry.BUCKET_VOLUME);
inputFluidStacks.put(r0, r0, inputFluidStack.copy());
outputFluidStacks.put(r0, r0, outputFluidStack.copy());
registerRecipe(outputFluidStack.copy(), r0.getInput().copy(), inputFluidStack.copy());
}
}
}
}
}
if (inputFluidStack == null) {
Log.warn("Ignoring invalid VAT recipe without input fluid/stacks");
}
}
output = new RecipeOutput[] { new RecipeOutput(outputFluidStack) };
energyRequired = recipe.getEnergyRequired();
this.inputStacks = recipe.getInputStacks();
valid = inputFluidStack != null && inputStacks != null && !inputStacks.isEmpty() && inputStacks.size() > 0
&& outputFluidStack != null;
}
@Override
public boolean isValid() {
return valid;
}
@Override
public int getEnergyRequired() {
return energyRequired;
}
@Override
public RecipeOutput[] getOutputs() {
return output;
}
@Override
public RecipeInput[] getInputs() {
return inputs;
}
@Override
public List<ItemStack> getInputStacks() {
return inputStacks;
}
@Override
public RecipeBonusType getBonusType() {
return RecipeBonusType.NONE;
}
private RecipeInput getRecipeInput(int slot, ItemStack item) {
if(item == null) {
return null;
}
for (RecipeInput ri : inputs) {
if (ri.getSlotNumber() == slot && ri.isInput(item)) {
return ri;
}
}
return null;
}
@Override
public boolean isValidInput(int slot, ItemStack item) {
return getRecipeInput(slot, item) != null;
}
@Override
public boolean isValidInput(FluidStack item) {
if(item == null) {
return false;
}
for (RecipeInput ri : inputs) {
if(item.getFluid() != null && item.isFluidEqual(ri.getFluidInput())) {
return true;
}
}
return false;
}
private static class RecipeMatch {
RecipeInput r0, r1;
FluidStack in, out;
void setRecipeInput(RecipeInput r) {
if (r != null) {
if (r.getSlotNumber() == 0) {
r0 = r;
} else {
r1 = r;
}
}
}
}
private RecipeMatch matchRecipe(MachineRecipeInput... inputs) {
if (!isValid() || inputs == null || inputs.length < requiredItems + 1) {
return null;
}
FluidStack inputFluid = null;
RecipeMatch m = new RecipeMatch();
for (MachineRecipeInput in : inputs) {
if(in.isFluid()) {
inputFluid = in.fluid;
} else {
m.setRecipeInput(getRecipeInput(in.slotNumber, in.item));
}
}
if (requiredItems == 1) {
m.r1 = m.r0;
}
m.in = inputFluidStacks.get(m.r0, m.r1);
m.out = outputFluidStacks.get(m.r0, m.r1);
if (inputFluid != null && inputFluid.containsFluid(m.in)) {
return m;
} else {
return null;
}
}
@Override
public boolean isInputForRecipe(MachineRecipeInput... inputs) {
RecipeMatch m = matchRecipe(inputs);
return m != null;
}
@Override
public List<FluidStack> getInputFluidStacks() {
throw new NotImplementedException("");
}
public float getMultiplierForInput(FluidStack item) {
for (RecipeInput input : inputs) {
if(input.isInput(item)) {
return input.getMulitplier();
}
}
return 1;
}
public FluidStack getRequiredFluidInput(MachineRecipeInput[] inputs) {
RecipeMatch m = matchRecipe(inputs);
if (m != null) {
return m.in;
} else {
// inputs are no valid recipe.
return new FluidStack(FluidRegistry.WATER, FluidContainerRegistry.BUCKET_VOLUME * 999);
}
}
public FluidStack getFluidOutput(MachineRecipeInput... inputs) {
RecipeMatch m = matchRecipe(inputs);
if (m != null) {
return m.out;
} else {
// inputs are no valid recipe.
return new FluidStack(FluidRegistry.WATER, 0);
}
}
public int getNumConsumed(ItemStack item) {
for (RecipeInput input : inputs) {
if(input.isInput(item)) {
return input.getInput().stackSize;
}
}
return 1;
}
}