content: package com.mekeng.github.common.part;
  
  import appeng.api.AEApi;
  import appeng.api.config.RedstoneMode;
  import appeng.api.config.Upgrades;
  import appeng.api.networking.ticking.IGridTickable;
  import appeng.api.networking.ticking.TickRateModulation;
  import appeng.api.parts.IPartCollisionHelper;
  import appeng.api.util.AECableType;
  import appeng.me.GridAccessException;
  import appeng.util.Platform;
  import com.mekeng.github.common.container.handler.GuiHandler;
  import com.mekeng.github.common.container.handler.MkEGuis;
  import com.mekeng.github.common.me.inventory.IConfigurableGasInventory;
  import com.mekeng.github.common.me.inventory.IGasInventory;
  import com.mekeng.github.common.me.inventory.impl.GasInventory;
  import com.mekeng.github.common.me.storage.IGasStorageChannel;
  import net.minecraft.entity.player.EntityPlayer;
  import net.minecraft.item.ItemStack;
  import net.minecraft.nbt.NBTTagCompound;
  import net.minecraft.tileentity.TileEntity;
  import net.minecraft.util.EnumHand;
  import net.minecraft.util.math.BlockPos;
  import net.minecraft.util.math.MathHelper;
  import net.minecraft.util.math.Vec3d;
  import net.minecraft.world.IBlockAccess;
  import net.minecraft.world.World;
  
  public abstract class PartSharedGasBus extends PartGasUpgradeable implements IGridTickable, IConfigurableGasInventory, IPartGroup {
  
      private final GasInventory config = new GasInventory(9);
      private boolean lastRedstone;
  
      public PartSharedGasBus(ItemStack is) {
          super(is);
      }
  
      @Override
      public void upgradesChanged() {
          this.updateState();
      }
  
      @Override
      public void onNeighborChanged(IBlockAccess w, BlockPos pos, BlockPos neighbor) {
          this.updateState();
          if (this.lastRedstone != this.getHost().hasRedstone(this.getSide())) {
              this.lastRedstone = !this.lastRedstone;
              if (this.lastRedstone && this.getRSMode() == RedstoneMode.SIGNAL_PULSE) {
                  this.doBusWork();
              }
          }
      }
  
      private void updateState() {
          try {
              if (!this.isSleeping()) {
                  this.getProxy().getTick().wakeDevice(this.getProxy().getNode());
              } else {
                  this.getProxy().getTick().sleepDevice(this.getProxy().getNode());
              }
          } catch (final GridAccessException e) {
              // :P
          }
      }
  
      @Override
      public boolean onPartActivate(final EntityPlayer player, final EnumHand hand, final Vec3d pos) {
          if (Platform.isServer()) {
              GuiHandler.openPartGui(player, this.getTile().getWorld(), this.getTile().getPos(), this.getSide().getFacing(), MkEGuis.GAS_IO_BUS);
          }
          return true;
      }
  
      @Override
      public void getBoxes(IPartCollisionHelper bch) {
          bch.addBox(6, 6, 11, 10, 10, 13);
          bch.addBox(5, 5, 13, 11, 11, 14);
          bch.addBox(4, 4, 14, 12, 12, 16);
      }
  
      protected TileEntity getConnectedTE() {
          TileEntity self = this.getHost().getTile();
          return this.getTileEntity(self, self.getPos().offset(this.getSide().getFacing()));
      }
  
      private TileEntity getTileEntity(final TileEntity self, final BlockPos pos) {
          final World w = self.getWorld();
  
          if (w.getChunkProvider().getLoadedChunk(pos.getX() >> 4, pos.getZ() >> 4) != null) {
              return w.getTileEntity(pos);
          }
  
          return null;
      }
  
      protected int calculateAmountToSend() {
          double amount = this.getChannel().transferFactor();
          switch (this.getInstalledUpgrades(Upgrades.SPEED)) {
              case 4:
                  amount = amount * 1.5;
              case 3:
                  amount = amount * 2;
              case 2:
                  amount = amount * 4;
              case 1:
                  amount = amount * 8;
              case 0:
              default:
                  return MathHelper.floor(amount);
          }
      }
  
      @Override
      public void readFromNBT(NBTTagCompound extra) {
          super.readFromNBT(extra);
          this.config.load(extra.getCompoundTag("io_config"));
      }
  
      @Override
      public void writeToNBT(NBTTagCompound extra) {
          super.writeToNBT(extra);
          extra.setTag("io_config", this.config.save());
      }
  
      public IGasInventory getConfig() {
          return this.config;
      }
  
      @Override
      public IGasInventory getGasInventoryByName(final String name) {
          if (name.equals("config")) {
              return this.config;
          }
          return null;
      }
  
      protected IGasStorageChannel getChannel() {
          return AEApi.instance().storage().getStorageChannel(IGasStorageChannel.class);
      }
  
      @Override
      public float getCableConnectionLength(AECableType cable) {
          return 5;
      }
  
      @Override
      public String getUnlocalizedGroupName() {
          return "group.mekeng.gas_io_bus";
      }
  
      protected abstract TickRateModulation doBusWork();
  
      protected abstract boolean canDoBusWork();
  
      public abstract boolean isExport();
  
  }
  