package erogenousbeef.bigreactors.client.gui;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.inventory.Container;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
import erogenousbeef.bigreactors.common.BigReactors;
import erogenousbeef.bigreactors.common.multiblock.block.BlockReactorPart;
import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedNetPort;
import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedNetPort.CircuitType;
import erogenousbeef.bigreactors.common.multiblock.tileentity.TileEntityReactorRedstonePort;
import erogenousbeef.bigreactors.gui.controls.BeefGuiLabel;
import erogenousbeef.bigreactors.gui.controls.GuiSelectableButton;
import erogenousbeef.bigreactors.net.CommonPacketHandler;
import erogenousbeef.bigreactors.net.message.ReactorRedstonePortChangeMessage;
public class GuiReactorRedstonePort extends BeefGuiBase {
private ResourceLocation _guiBackground;
private TileEntityReactorRedstonePort port;
BeefGuiLabel titleString;
BeefGuiLabel settingString;
private GuiButton commitBtn;
private GuiButton resetBtn;
// Subsetting display
private BeefGuiLabel subSettingLabel;
private GuiButton subInputButton;
private GuiButton subInputButton2;
private BeefGuiLabel subInputRodSettingLabel;
private GuiTextField subInputRodSetting; // Also used as the pulse activation setting
private BeefGuiLabel subInputRodSettingPctLabel;
private BeefGuiLabel subInputRodSettingOffLabel;
private GuiTextField subInputRodSettingOff;
private BeefGuiLabel subInputRodSettingOffPctLabel;
BeefGuiLabel subOutputValueLabel;
private GuiTextField subOutputValue;
// End Subsetting display
private Map<CircuitType, GuiSelectableButton> btnMap;
private int outputLevel;
private boolean greaterThan;
private boolean activeOnPulse;
private boolean retract;
private static final int MINIMUM_SETTING_SELECTOR_ID = 10;
public GuiReactorRedstonePort(Container container, TileEntityReactorRedstonePort tileentity) {
super(container);
_guiBackground = new ResourceLocation(BigReactors.GUI_DIRECTORY + "RedstonePort.png");
port = tileentity;
ySize = 204;
btnMap = new HashMap<CircuitType, GuiSelectableButton>();
outputLevel = tileentity.getOutputLevel();
greaterThan = tileentity.getGreaterThan();
activeOnPulse = tileentity.isInputActiveOnPulse();
if(outputLevel < 0) {
retract = true;
outputLevel = Math.abs(outputLevel);
}
else {
retract = false;
}
}
@Override
public ResourceLocation getGuiBackground() {
return _guiBackground;
}
private void registerCircuitButton(CircuitType ct, GuiSelectableButton btn) {
this.btnMap.put(ct, btn);
registerControl(btn);
}
@Override
public void initGui() {
super.initGui();
int leftX = guiLeft + 6;
int topY = guiTop + 6;
titleString = new BeefGuiLabel(this, "Reactor Redstone Port", leftX+2, topY);
topY += titleString.getHeight() + 4;
settingString = new BeefGuiLabel(this, "Pick a setting", leftX, topY);
topY += settingString.getHeight() + 4;
// Setting picker
BlockReactorPart reactorPartBlock = (BlockReactorPart)BigReactors.blockReactorPart;
int buttonOrdinal = MINIMUM_SETTING_SELECTOR_ID;
leftX = guiLeft + 16;
CircuitType currentCircuitType = port.getCircuitType();
for(CircuitType ct : CircuitType.values()) {
if(ct == CircuitType.DISABLED) { continue; }
GuiSelectableButton newBtn = new GuiSelectableButton(buttonOrdinal++, leftX, topY, reactorPartBlock.getRedNetConfigIcon(ct), 0xFF00FF00, this);
newBtn.displayString = GuiReactorRedNetPort.grabbableTooltips[ct.ordinal()-1];
if(ct == currentCircuitType) {
newBtn.setSelected(true);
}
leftX += 28;
if(leftX > guiLeft + 130) {
topY += 28;
leftX = guiLeft + 16;
}
registerCircuitButton(ct, newBtn);
}
topY += 32;
leftX = guiLeft + 6;
// Subsetting display
subSettingLabel = new BeefGuiLabel(this, "Settings", leftX, topY);
topY += subSettingLabel.getHeight() + 4;
subInputButton = new GuiButton(2, leftX, topY, 100, 20, "Activate on Pulse");
subInputButton2 = new GuiButton(3, leftX + xSize - 46, topY, 36, 20, "Mode");
topY += 24;
subInputRodSettingLabel = new BeefGuiLabel(this, "While On", leftX, topY);
subInputRodSettingOffLabel = new BeefGuiLabel(this, "While Off", leftX + xSize/2, topY);
subOutputValue = new GuiTextField(this.fontRendererObj, leftX, topY, 60, 12);
subOutputValue.setCanLoseFocus(true);
subOutputValue.setMaxStringLength(7);
subOutputValue.setText("0");
subOutputValue.setEnabled(true);
subOutputValueLabel = new BeefGuiLabel(this, "C", leftX + 62, topY + 2);
topY += subInputRodSettingLabel.getHeight() + 2;
subInputRodSetting = new GuiTextField(this.fontRendererObj, leftX, topY, 32, 12);
subInputRodSetting.setCanLoseFocus(true);
subInputRodSetting.setMaxStringLength(3);
subInputRodSetting.setText("0");
subInputRodSetting.setEnabled(true);
subInputRodSettingPctLabel = new BeefGuiLabel(this, "%", leftX + 34, topY + 2);
subInputRodSettingOff = new GuiTextField(this.fontRendererObj, leftX + xSize/2, topY, 32, 12);
subInputRodSettingOff.setCanLoseFocus(true);
subInputRodSettingOff.setMaxStringLength(3);
subInputRodSettingOff.setText("0");
subInputRodSettingOff.setEnabled(true);
subInputRodSettingOffPctLabel = new BeefGuiLabel(this, "%", leftX + xSize/2 + 34, topY + 2);
topY += 24;
// Bottom buttons
commitBtn = new GuiButton(0, guiLeft + xSize - 60, guiTop + ySize - 24, 56, 20, "Commit");
commitBtn.enabled = false;
resetBtn = new GuiButton(1, guiLeft + 4, guiTop + ySize - 24, 56, 20, "Reset");
registerControl(titleString);
registerControl(settingString);
registerControl(subSettingLabel);
registerControl(subInputButton);
registerControl(subInputButton2);
registerControl(subInputRodSettingLabel);
registerControl(subInputRodSettingOffLabel);
registerControl(subInputRodSetting);
registerControl(subInputRodSettingOff);
registerControl(subInputRodSettingPctLabel);
registerControl(subInputRodSettingOffPctLabel);
registerControl(subOutputValue);
registerControl(subOutputValueLabel);
registerControl(commitBtn);
registerControl(resetBtn);
if(currentCircuitType == CircuitType.inputSetControlRod) {
subInputRodSetting.setText(Integer.toString(TileEntityReactorRedstonePort.unpackControlRodLevelOn(this.outputLevel)));
subInputRodSettingOff.setText(Integer.toString(TileEntityReactorRedstonePort.unpackControlRodLevelOff(this.outputLevel)));
}
else if(TileEntityReactorRedNetPort.isOutput(currentCircuitType)) {
subOutputValue.setText(Integer.toString(this.outputLevel));
}
updateSubSettings(currentCircuitType);
if(TileEntityReactorRedNetPort.isInput(currentCircuitType)) {
validateInputValues();
}
else {
validateOutputValues();
}
}
@Override
public void updateScreen() {
super.updateScreen();
CircuitType selectedSetting = getUserSelectedCircuitType();
updateSubSettings(selectedSetting);
if(selectedSetting == port.getCircuitType()) {
int actualOutputLevel = this.outputLevel;
if(selectedSetting == CircuitType.inputSetControlRod && this.greaterThan && this.retract) { actualOutputLevel *= -1; }
if(this.activeOnPulse != port.isInputActiveOnPulse() ||
this.greaterThan != port.getGreaterThan() ||
actualOutputLevel != port.getOutputLevel()) {
commitBtn.enabled = true;
}
else {
commitBtn.enabled = false;
}
}
else {
commitBtn.enabled = true;
}
}
private void updateSubSettings(CircuitType selectedSetting) {
this.subSettingLabel.setLabelText(getLabelFromSelectedSubSetting(selectedSetting));
updateSubSettingInputButton(selectedSetting);
updateSubSettingTextFields(selectedSetting);
}
private String getLabelFromSelectedSubSetting(CircuitType selectedSetting) {
switch(selectedSetting) {
case inputActive: return "Input - Enable/Disable";
case inputEjectWaste: return "Input - Eject Waste";
case inputSetControlRod: return "Input - Control Rod Insertion";
case outputFuelAmount: return "Output - Fuel Amount";
case outputWasteAmount: return "Output - Waste Amount";
case outputFuelMix: return "Output - Fuel Enrichment %";
case outputFuelTemperature: return "Output - Fuel Temp (C)";
case outputCasingTemperature: return "Output - Casing Temp (C)";
case outputEnergyAmount: return "Output - Energy Amount (%)";
default:
return "";
}
}
private void updateSubSettingInputButton(CircuitType selectedSetting) {
subInputButton.visible = true;
subInputButton2.visible = false;
switch(selectedSetting) {
case inputActive:
subInputButton.enabled = true;
if(this.activeOnPulse) {
subInputButton.displayString = "Toggle on Pulse";
}
else {
subInputButton.displayString = "Set from Signal";
}
break;
case inputSetControlRod:
subInputButton.enabled = true;
if(this.activeOnPulse) {
subInputButton2.visible = true;
if(this.greaterThan) {
if(this.retract) {
subInputButton.displayString = "Retract on Pulse";
}
else {
subInputButton.displayString = "Insert on Pulse";
}
}
else {
subInputButton.displayString = "Set on Pulse";
}
}
else {
subInputButton.displayString = "Set from Signal";
}
break;
case inputEjectWaste:
subInputButton.enabled = false;
subInputButton.displayString = "Eject on Pulse";
break;
case outputFuelTemperature:
case outputCasingTemperature:
case outputFuelMix:
case outputFuelAmount:
case outputWasteAmount:
case outputEnergyAmount:
subInputButton.enabled = true;
if(this.greaterThan) {
subInputButton.displayString = "Active While Above";
}
else {
subInputButton.displayString = "Active While Below";
}
break;
default:
subInputButton.visible = false;
}
}
private void updateSubSettingTextFields(CircuitType selectedSetting) {
subOutputValueLabel.setLabelText("");
subInputRodSettingLabel.setLabelText("");
subInputRodSettingPctLabel.setLabelText("");
subInputRodSettingOffLabel.setLabelText("");
subInputRodSettingOffPctLabel.setLabelText("");
subOutputValueLabel.setLabelTooltip("");
subInputRodSetting.setVisible(false);
subInputRodSettingOff.setVisible(false);
subOutputValue.setVisible(false);
switch(selectedSetting) {
case outputFuelTemperature:
case outputCasingTemperature:
subOutputValueLabel.setLabelText("C");
subOutputValueLabel.setLabelTooltip("Degrees centigrade");
subOutputValue.setVisible(true);
break;
case outputFuelMix:
subOutputValueLabel.setLabelText("%");
subOutputValueLabel.setLabelTooltip("% of total contents, 0% if empty");
subOutputValue.setVisible(true);
break;
case outputEnergyAmount:
subOutputValueLabel.setLabelText("%");
subOutputValueLabel.setLabelTooltip("% of energy buffer filled, 0% if empty");
subOutputValue.setVisible(true);
break;
case outputFuelAmount:
subOutputValueLabel.setLabelText("mB");
subOutputValueLabel.setLabelTooltip("Milli-buckets");
subOutputValue.setVisible(true);
break;
case outputWasteAmount:
subOutputValueLabel.setLabelText("mB");
subOutputValueLabel.setLabelTooltip("Milli-buckets");
subOutputValue.setVisible(true);
break;
case inputSetControlRod:
if(this.activeOnPulse) {
if(this.greaterThan) {
if(this.retract) {
subInputRodSettingLabel.setLabelText("Retract by");
}
else {
subInputRodSettingLabel.setLabelText("Insert by");
}
}
else {
subInputRodSettingLabel.setLabelText("Set to");
}
}
else {
subInputRodSettingLabel.setLabelText("While On");
subInputRodSettingOffLabel.setLabelText("While Off");
subInputRodSettingOffPctLabel.setLabelText("%");
subInputRodSettingOff.setVisible(true);
}
subInputRodSetting.setVisible(true);
subInputRodSettingPctLabel.setLabelText("%");
break;
default:
break;
}
}
@Override
protected void actionPerformed(GuiButton clickedButton) {
if(clickedButton.id == 0) {
CircuitType newCircuitType = getUserSelectedCircuitType();
int actualOutputLevel = this.outputLevel;
if(newCircuitType == CircuitType.inputSetControlRod && this.greaterThan && this.retract) { actualOutputLevel *= -1; }
CommonPacketHandler.INSTANCE.sendToServer(new ReactorRedstonePortChangeMessage(port, newCircuitType.ordinal(), actualOutputLevel, this.greaterThan, this.activeOnPulse));
}
else if(clickedButton.id == 1) {
for(Entry<CircuitType, GuiSelectableButton> pair : btnMap.entrySet()) {
pair.getValue().setSelected(pair.getKey() == port.getCircuitType());
}
setSubSettingsToDefaults(port.getCircuitType());
}
else if(clickedButton.id == 2) {
CircuitType selectedCircuitType = this.getUserSelectedCircuitType();
if(TileEntityReactorRedNetPort.isInput(selectedCircuitType))
this.activeOnPulse = !this.activeOnPulse;
else
this.greaterThan = !this.greaterThan;
}
else if(clickedButton.id == 3) {
if(this.greaterThan && !this.retract) {
// Insert -> Retract
this.greaterThan = true;
this.retract = true;
}
else if(this.greaterThan && this.retract) {
// Retract -> Set
this.greaterThan = false;
this.retract = false;
}
else {
// Set -> Insert
this.greaterThan = true;
this.retract = false; // Doesn't actually matter, but hey, keeping it tidy.
}
}
else if(clickedButton.id >= MINIMUM_SETTING_SELECTOR_ID && clickedButton.id < MINIMUM_SETTING_SELECTOR_ID + btnMap.size()) {
CircuitType ct = CircuitType.DISABLED;
for(Entry<CircuitType, GuiSelectableButton> pair : btnMap.entrySet()) {
GuiSelectableButton btn = pair.getValue();
btn.setSelected(btn.id == clickedButton.id);
if(btn.isSelected()) {
ct = pair.getKey();
}
}
setSubSettingsToDefaults(ct);
}
}
private void setSubSettingsToDefaults(CircuitType selectedType) {
if(port.getCircuitType() == selectedType) {
// RESTORE ALL THE DEFAULTS
this.outputLevel = port.getOutputLevel();
this.greaterThan = port.getGreaterThan();
this.activeOnPulse = port.isInputActiveOnPulse();
if(this.outputLevel < 0) {
this.retract = true;
this.outputLevel = Math.abs(this.outputLevel);
}
else {
this.retract = false;
}
}
else {
this.greaterThan = true;
this.activeOnPulse = false;
this.outputLevel = 0;
// We do this so the state of the fields is accurate for the following two methods
updateSubSettingTextFields(selectedType);
// This should reset outputLevel from stored values
if(TileEntityReactorRedNetPort.isInput(selectedType)) {
this.validateInputValues();
}
else {
this.validateOutputValues();
}
}
this.subInputRodSetting.setFocused(false);
this.subInputRodSettingOff.setFocused(false);
this.subOutputValue.setFocused(false);
}
// Allow 0-9 (regular or numpad), backspace, delete, left/right arrows.
private boolean isKeyValidForValueInput(int keyCode) {
if(keyCode >= Keyboard.KEY_1 && keyCode <= Keyboard.KEY_0) { return true; }
switch(keyCode) {
case Keyboard.KEY_NUMPAD0:
case Keyboard.KEY_NUMPAD1:
case Keyboard.KEY_NUMPAD2:
case Keyboard.KEY_NUMPAD3:
case Keyboard.KEY_NUMPAD4:
case Keyboard.KEY_NUMPAD5:
case Keyboard.KEY_NUMPAD6:
case Keyboard.KEY_NUMPAD7:
case Keyboard.KEY_NUMPAD8:
case Keyboard.KEY_NUMPAD9:
case Keyboard.KEY_DELETE:
case Keyboard.KEY_BACK:
case Keyboard.KEY_LEFT:
case Keyboard.KEY_RIGHT:
return true;
default:
return false;
}
}
@Override
protected void keyTyped(char inputChar, int keyCode) {
boolean isAnyTextboxFocused = this.subInputRodSetting.isFocused() ||
this.subInputRodSettingOff.isFocused() ||
this.subOutputValue.isFocused();
if (keyCode == Keyboard.KEY_ESCAPE ||
(!isAnyTextboxFocused && keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode())) {
this.mc.thePlayer.closeScreen();
}
// Allow arrow keys, 0-9, and delete
if(isKeyValidForValueInput(keyCode)) {
if(this.subInputRodSetting.isFocused()) {
this.subInputRodSetting.textboxKeyTyped(inputChar, keyCode);
validateInputValues();
}
if(this.subInputRodSettingOff.isFocused()) {
this.subInputRodSettingOff.textboxKeyTyped(inputChar, keyCode);
validateInputValues();
}
if(this.subOutputValue.isFocused()) {
this.subOutputValue.textboxKeyTyped(inputChar, keyCode);
validateOutputValues();
}
}
if(keyCode == Keyboard.KEY_TAB) {
/// ffffffuuuuuuuck tabbing
if(this.subOutputValue.isFocused()) {
this.subOutputValue.setFocused(false);
}
else if(this.subOutputValue.getVisible()) {
this.subOutputValue.setFocused(true);
}
if(this.subInputRodSettingOff.getVisible()) {
if(this.subInputRodSetting.isFocused()) {
this.subInputRodSetting.setFocused(false);
this.subInputRodSettingOff.setFocused(true);
}
else if(this.subInputRodSettingOff.isFocused()) {
this.subInputRodSettingOff.setFocused(false);
}
else {
this.subInputRodSetting.setFocused(true);
}
}
else if(this.subInputRodSetting.getVisible()) {
if(this.subInputRodSetting.isFocused()) {
this.subInputRodSetting.setFocused(false);
}
else {
this.subInputRodSetting.setFocused(true);
}
}
// Else, nothing is visible, nothing is focused, screw you.
}
if(keyCode == Keyboard.KEY_RETURN && isAnyTextboxFocused) {
this.subInputRodSetting.setFocused(false);
this.subInputRodSettingOff.setFocused(false);
this.subOutputValue.setFocused(false);
}
}
private void validateInputValues() {
outputLevel = 0;
String in1 = this.subInputRodSetting.getText();
int val1;
if(in1.isEmpty()) {
val1 = 0;
}
else {
val1 = Integer.parseInt(in1);
if(val1 < 0) { val1 = 0; }
else if(val1 > 100) { val1 = 100; }
}
this.subInputRodSetting.setText(Integer.toString(val1));
if(this.subInputRodSettingOff.getVisible()) {
int val2;
String in2 = this.subInputRodSettingOff.getText();
if(in2.isEmpty()) {
val2 = 0;
}
else {
val2 = Integer.parseInt(in2);
if(val2 < 0) { val2 = 0; }
else if(val2 > 100) { val2 = 100; }
}
// pack into high-order bits
this.outputLevel = (val2 << 8) & 0xFF00;
this.subInputRodSettingOff.setText(Integer.toString(val2));
}
else {
// Preserve high-order bits
this.outputLevel = this.outputLevel & 0xFF00;
}
// Pack in low-order bits
this.outputLevel |= val1 & 0xFF;
}
private void validateOutputValues() {
CircuitType selectedType = getUserSelectedCircuitType();
int maxVal = Integer.MAX_VALUE;
if(selectedType == CircuitType.outputFuelMix || selectedType == CircuitType.outputEnergyAmount) {
// Percentile
maxVal = 100;
}
String in1 = this.subOutputValue.getText();
int val1;
if(in1.isEmpty()) {
val1 = 0;
}
else {
val1 = Integer.parseInt(in1);
if(val1 < 0) { val1 = 0; }
else if(val1 > maxVal) { val1 = maxVal; }
}
this.subOutputValue.setText(Integer.toString(val1));
this.outputLevel = val1;
}
private CircuitType getUserSelectedCircuitType() {
for(Entry<CircuitType, GuiSelectableButton> pair : btnMap.entrySet()) {
if(pair.getValue().isSelected()) {
return pair.getKey();
}
}
return CircuitType.DISABLED;
}
}