content: package mods.eln.sim;
  
  import mods.eln.misc.Recipe;
  import mods.eln.misc.RecipesList;
  import mods.eln.misc.Utils;
  import mods.eln.sim.mna.component.Resistor;
  import net.minecraft.inventory.IInventory;
  import net.minecraft.item.ItemStack;
  
  public class ElectricalStackMachineProcess implements IProcess {
  
      ElectricalStackMachineProcessObserver observer;
  
      public IInventory inventory;
      int inputSlotId, OutputSlotId, outputSlotNbr;
      Resistor electricalResistor;
      double resistorValue;
      RecipesList recipesList;
      int[] outSlotIdList;
      double efficiency = 1.0, speedUp = 1.0;
  
      ItemStack itemStackInOld = null;
  
      boolean smeltInProcess = false;
      double energyNeeded = 0;
      double energyCounter = 0;
  
      public interface ElectricalStackMachineProcessObserver {
          void done(ElectricalStackMachineProcess who);
      }
  
      public void setObserver(ElectricalStackMachineProcessObserver observer) {
          this.observer = observer;
      }
  
      public ElectricalStackMachineProcess(IInventory inventory, int inputSlotId, int OutputSlotId, int outputSlotNbr,
                                           Resistor electricalResistor, double resistorValue, RecipesList recipesList) {
          this.inventory = inventory;
          this.inputSlotId = inputSlotId;
          this.OutputSlotId = OutputSlotId;
          this.outputSlotNbr = outputSlotNbr;
          this.electricalResistor = electricalResistor;
          this.resistorValue = resistorValue;
          this.recipesList = recipesList;
  
          outSlotIdList = new int[outputSlotNbr];
  
          for (int idx = 0; idx < outputSlotNbr; idx++) {
              outSlotIdList[idx] = idx + OutputSlotId;
          }
      }
  
      public void setEfficiency(double efficiency) {
          this.efficiency = efficiency;
      }
  
      public void setSpeedUp(double speedUp) {
          this.speedUp = speedUp;
          setResistorValue(resistorValue);
      }
  
      @Override
      public void process(double time) {
          ItemStack itemStackIn = inventory.getStackInSlot(inputSlotId);
  
          boolean itemTypeChanged = itemStackIn == null && itemStackInOld != null || itemStackIn != null && itemStackInOld == null || itemStackIn != null && !itemStackIn.getUnlocalizedName().equals(itemStackInOld.getUnlocalizedName());
  
          if (itemTypeChanged || (!smeltCan()) || !smeltInProcess) {
              smeltInit();
              itemStackInOld = itemStackIn;
          }
  
          if (smeltInProcess) {
              energyCounter += getPower() * time;
              if (energyCounter > energyNeeded) {
                  energyCounter -= energyNeeded;
                  smeltItem();
                  smeltInit();
              }
          }
      }
  
      public double getPower() {
          return electricalResistor.getPower() * efficiency;
      }
  
      public void smeltInit() {
          smeltInProcess = smeltCan();
          if (!smeltInProcess) {
              energyNeeded = 1.0;
              energyCounter = 0.0;
              electricalResistor.highImpedance();
          } else {
              energyNeeded = recipesList.getRecipe(inventory.getStackInSlot(inputSlotId)).energy;
              energyCounter = 0.0;
              electricalResistor.setResistance(resistorValue / speedUp);
          }
      }
  
      public void setResistorValue(double value) {
          resistorValue = value;
          if (smeltInProcess) electricalResistor.setResistance(resistorValue / speedUp);
      }
  
      /**
       * Returns true if the furnace can smelt an item, i.e. has a source item, destination stack isn't full, etc.
       */
      public boolean smeltCan() {
          if (inventory.getStackInSlot(inputSlotId) == null) {
              return false;
          } else {
              ItemStack[] output = getSmeltResult();
              if (output == null) return false;
              return Utils.canPutStackInInventory(getSmeltResult(), inventory, outSlotIdList);
          }
      }
  
      public ItemStack[] getSmeltResult() {
          Recipe recipe = recipesList.getRecipe(inventory.getStackInSlot(inputSlotId));
          if (recipe == null) return null;
          return recipe.output;
      }
  
      /**
       * Turn one item from the furnace source stack into the appropriate smelted item in the furnace result stack
       */
      public void smeltItem() {
          if (this.smeltCan()) {
              Recipe recipe = recipesList.getRecipe(inventory.getStackInSlot(inputSlotId));
              Utils.tryPutStackInInventory(recipe.getOutputCopy(), inventory, outSlotIdList);
              inventory.decrStackSize(inputSlotId, recipe.input.stackSize);
              if (observer != null) observer.done(this);
          }
      }
  
      public double processState() {
          if (!smeltInProcess) return 0.0;
          double state = energyCounter / energyNeeded;
          if (state > 1.0) state = 1.0;
          return state;
      }
  
      public double processStatePerSecond() {
          if (!smeltInProcess) return 0;
          double power = getPower() + 0.1;
          return power / (energyNeeded);
      }
  }
  