package net.scapeemulator.game.model.player.interfaces;
import static net.scapeemulator.game.msg.impl.inter.InterfaceOpenMessage.CLOSABLE;
import static net.scapeemulator.game.msg.impl.inter.InterfaceOpenMessage.STATIC;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.scapeemulator.game.model.player.Player;
import net.scapeemulator.game.msg.impl.inter.InterfaceCloseMessage;
import net.scapeemulator.game.msg.impl.inter.InterfaceOpenMessage;
import net.scapeemulator.game.msg.impl.inter.InterfaceRootMessage;
public final class InterfaceSet {
private static final int UNSET = -1;
private static final int FIXED_TAB_OFFSET = 83;
private static final int RESIZABLE_TAB_OFFSET = 93;
/**
* The enumeration for each of the display modes.
*/
public enum DisplayMode {
FIXED,
RESIZABLE;
}
/**
* The enumeration for each of the component types.
*/
public enum ComponentType {
/**
* Each of the fixed interface components.
*/
WINDOW_FIXED(Interface.FIXED, 11),
OVERLAY_FIXED(Interface.FIXED, 5),
CHAT_OPTIONS_FIXED(Interface.FIXED, 14, 751),
CHATBOX_FIXED(Interface.FIXED, 75, 752),
PM_CHAT_FIXED(Interface.FIXED, 10, 754),
HITPOINTS_ORB_FIXED(Interface.FIXED, 70, Interface.HITPOINTS_ORB),
PRAYER_ORB_FIXED(Interface.FIXED, 71, Interface.PRAYER_ORB),
ENERGY_ORB_FIXED(Interface.FIXED, 72, Interface.ENERGY_ORB),
// SUMMONING_ORB_FIXED(Interface.FIXED, 67, Interface.SUMMONING_ORB),
ATTACK_TAB_FIXED(Interface.FIXED, Tab.ATTACK + FIXED_TAB_OFFSET, UNSET),
SKILL_TAB_FIXED(Interface.FIXED, Tab.SKILLS + FIXED_TAB_OFFSET, Interface.SKILLS),
QUEST_TAB_FIXED(Interface.FIXED, Tab.QUEST + FIXED_TAB_OFFSET, Interface.QUESTS),
INVENTORY_TAB_FIXED(Interface.FIXED, Tab.INVENTORY + FIXED_TAB_OFFSET, Interface.INVENTORY),
EQUIPMENT_TAB_FIXED(Interface.FIXED, Tab.EQUIPMENT + FIXED_TAB_OFFSET, Interface.EQUIPMENT),
PRAYER_TAB_FIXED(Interface.FIXED, Tab.PRAYER + FIXED_TAB_OFFSET, Interface.PRAYER),
MAGIC_TAB_FIXED(Interface.FIXED, Tab.MAGIC + FIXED_TAB_OFFSET, Interface.MAGIC),
FRIENDS_TAB_FIXED(Interface.FIXED, Tab.FRIENDS + FIXED_TAB_OFFSET, Interface.FRIENDS),
IGNORES_TAB_FIXED(Interface.FIXED, Tab.IGNORES + FIXED_TAB_OFFSET, Interface.IGNORES),
CLAN_TAB_FIXED(Interface.FIXED, Tab.CLAN + FIXED_TAB_OFFSET, Interface.CLAN),
SETTINGS_TAB_FIXED(Interface.FIXED, Tab.SETTINGS + FIXED_TAB_OFFSET, Interface.SETTINGS),
EMOTES_TAB_FIXED(Interface.FIXED, Tab.EMOTES + FIXED_TAB_OFFSET, Interface.EMOTES),
MUSIC_TAB_FIXED(Interface.FIXED, Tab.MUSIC + FIXED_TAB_OFFSET, Interface.MUSIC),
LOGOUT_TAB_FIXED(Interface.FIXED, Tab.LOGOUT + FIXED_TAB_OFFSET, Interface.LOGOUT),
/* Each of the resizable interface components. */
WINDOW_RESIZABLE(Interface.RESIZABLE, 6),
OVERLAY_RESIZABLE(Interface.RESIZABLE, 5),
CHAT_OPTIONS_RESIZABLE(Interface.RESIZABLE, 23, 751),
CHATBOX_RESIZABLE(Interface.RESIZABLE, 70, 752),
PM_CHAT_RESIZABLE(Interface.RESIZABLE, 71, 754),
HITPOINTS_ORB_RESIZABLE(Interface.RESIZABLE, 13, Interface.HITPOINTS_ORB),
PRAYER_ORB_RESIZABLE(Interface.RESIZABLE, 14, Interface.PRAYER_ORB),
ENERGY_ORB_RESIZABLE(Interface.RESIZABLE, 15, Interface.ENERGY_ORB),
// SUMMONING_ORB_RESIZABLE(Interface.RESIZABLE, 16, Interface.SUMMONING_ORB),
ATTACK_TAB_RESIZABLE(Interface.RESIZABLE, Tab.ATTACK + RESIZABLE_TAB_OFFSET, UNSET),
SKILL_TAB_RESIZABLE(Interface.RESIZABLE, Tab.SKILLS + RESIZABLE_TAB_OFFSET, Interface.SKILLS),
QUEST_TAB_RESIZABLE(Interface.RESIZABLE, Tab.QUEST + RESIZABLE_TAB_OFFSET, Interface.QUESTS),
INVENTORY_TAB_RESIZABLE(Interface.RESIZABLE, Tab.INVENTORY + RESIZABLE_TAB_OFFSET, Interface.INVENTORY),
EQUIPMENT_TAB_RESIZABLE(Interface.RESIZABLE, Tab.EQUIPMENT + RESIZABLE_TAB_OFFSET, Interface.EQUIPMENT),
PRAYER_TAB_RESIZABLE(Interface.RESIZABLE, Tab.PRAYER + RESIZABLE_TAB_OFFSET, Interface.PRAYER),
MAGIC_TAB_RESIZABLE(Interface.RESIZABLE, Tab.MAGIC + RESIZABLE_TAB_OFFSET, Interface.MAGIC),
FRIENDS_TAB_RESIZABLE(Interface.RESIZABLE, Tab.FRIENDS + RESIZABLE_TAB_OFFSET, Interface.FRIENDS),
IGNORES_TAB_RESIZABLE(Interface.RESIZABLE, Tab.IGNORES + RESIZABLE_TAB_OFFSET, Interface.IGNORES),
CLAN_TAB_RESIZABLE(Interface.RESIZABLE, Tab.CLAN + RESIZABLE_TAB_OFFSET, Interface.CLAN),
SETTINGS_TAB_RESIZABLE(Interface.RESIZABLE, Tab.SETTINGS + RESIZABLE_TAB_OFFSET, Interface.SETTINGS),
EMOTES_TAB_RESIZABLE(Interface.RESIZABLE, Tab.EMOTES + RESIZABLE_TAB_OFFSET, Interface.EMOTES),
MUSIC_TAB_RESIZABLE(Interface.RESIZABLE, Tab.MUSIC + RESIZABLE_TAB_OFFSET, Interface.MUSIC),
LOGOUT_TAB_RESIZABLE(Interface.RESIZABLE, Tab.LOGOUT + RESIZABLE_TAB_OFFSET, Interface.LOGOUT),
/* Other components. */
CHATBOX_INPUT(752, 8, 137),
CHATBOX_OVERLAY(752, 12, UNSET);
/**
* Each of the lists for components of each display mode.
*/
private static List<ComponentType> fixedComponents, resizableComponents;
private final int widgetId, componentId, defaultId, mode;
ComponentType(int widgetId, int componentId) {
this(widgetId, componentId, UNSET, CLOSABLE);
}
ComponentType(int widgetId, int componentId, int defaultId) {
this(widgetId, componentId, defaultId, STATIC);
}
ComponentType(int widgetId, int componentId, int defaultId, int mode) {
this.widgetId = widgetId;
this.componentId = componentId;
this.defaultId = defaultId;
this.mode = mode;
}
public int getWidgetId() {
return widgetId;
}
public int getComponentId() {
return componentId;
}
public int getDefaultId() {
return defaultId;
}
public int getMode() {
return mode;
}
public static ComponentType getWindow(DisplayMode mode) {
switch (mode) {
case FIXED:
return WINDOW_FIXED;
case RESIZABLE:
return WINDOW_RESIZABLE;
}
throw new RuntimeException();
}
public static ComponentType getOverlay(DisplayMode mode) {
switch (mode) {
case FIXED:
return OVERLAY_FIXED;
case RESIZABLE:
return OVERLAY_RESIZABLE;
}
throw new RuntimeException();
}
public static ComponentType getAttackTab(DisplayMode mode) {
switch (mode) {
case FIXED:
return ATTACK_TAB_FIXED;
case RESIZABLE:
return ATTACK_TAB_RESIZABLE;
}
throw new RuntimeException();
}
public static ComponentType getInventoryTab(DisplayMode mode) {
switch (mode) {
case FIXED:
return INVENTORY_TAB_FIXED;
case RESIZABLE:
return INVENTORY_TAB_RESIZABLE;
}
throw new RuntimeException();
}
public static List<ComponentType> getComponentTypes(DisplayMode mode) {
switch (mode) {
case FIXED:
if (fixedComponents == null) {
fixedComponents = new LinkedList<>();
for (ComponentType type : values()) {
if (type.name().endsWith("FIXED")) {
fixedComponents.add(type);
}
}
fixedComponents.add(CHATBOX_INPUT);
fixedComponents.add(CHATBOX_OVERLAY);
}
return fixedComponents;
case RESIZABLE:
if (resizableComponents == null) {
resizableComponents = new LinkedList<>();
for (ComponentType type : values()) {
if (type.name().endsWith("RESIZABLE")) {
resizableComponents.add(type);
}
}
resizableComponents.add(CHATBOX_INPUT);
resizableComponents.add(CHATBOX_OVERLAY);
}
return resizableComponents;
}
throw new RuntimeException();
}
}
/**
* The component class.
*/
public class Component {
private final ComponentType type;
private ComponentListener listener;
private int currentId;
/**
* Constructs a new {@link Component};
*
* @param type The component type that this component is based off of.
*/
public Component(ComponentType type) {
this.type = type;
currentId = type.getDefaultId();
}
/**
* Gets the current widget id.
*/
public int getCurrentId() {
return currentId;
}
/**
* Attaches a listener to the component.
*/
public Component setListener(ComponentListener listener) {
if (this.listener != null) {
throw new IllegalStateException("Attempted to overwrite listener " + this.listener.getClass() + " with " + listener.getClass()
+ ". Ensure previous listener properly handles close/change events.");
}
this.listener = listener;
return this;
}
/**
* Removes the listener from the component.
*/
public void removeListener() {
listener = null;
}
/**
* Sets the current widget id.
*/
private Component set(int id) {
if (currentId != id) {
if (listener != null) {
boolean shouldKeepListener = listener.componentChanged(this, currentId);
if (!shouldKeepListener) {
listener = null;
}
}
}
currentId = id;
return this;
}
/**
* Alerts the listener that an input for the interface was pressed.
*/
public void alertInputPressed(int componentId, int dynamicId) {
if (listener != null) {
listener.inputPressed(this, componentId, dynamicId);
}
}
/**
* Refreshes the component by sending an open interface message to the player.
*/
public void refresh() {
if (currentId != UNSET) {
player.send(new InterfaceOpenMessage(type.getWidgetId(), type.getComponentId(), currentId, type.getMode()));
}
}
/**
* Resets the component; if the component is static refreshes the component and if it is closable will request that the client close that
* interface.
*/
public void reset() {
switch (type.getMode()) {
case STATIC:
if (currentId != type.getDefaultId()) {
currentId = type.getDefaultId();
if (currentId != UNSET) {
refresh();
return;
}
/* Close the interface if it is just going to go back to being unset */
player.send(new InterfaceCloseMessage(type.getWidgetId(), type.getComponentId()));
if (listener != null) {
listener.componentClosed(this);
listener = null;
}
}
break;
case CLOSABLE:
if (currentId != UNSET) {
player.send(new InterfaceCloseMessage(type.getWidgetId(), type.getComponentId()));
currentId = UNSET;
if (listener != null) {
listener.componentClosed(this);
listener = null;
}
}
break;
}
}
}
/**
* The player to send updates to when interfaces are opened or closed.
*/
private final Player player;
/**
* Each of the components that the player can have opened.
*/
private final Map<ComponentType, Component> components = new HashMap<>();
private DisplayMode mode = DisplayMode.FIXED;
public InterfaceSet(Player player) {
this.player = player;
}
public DisplayMode getDisplayMode() {
return mode;
}
public void setDisplayMode(DisplayMode mode) {
this.mode = mode;
}
public void init() {
/* Send the proper root widget */
switch (mode) {
case FIXED:
player.send(new InterfaceRootMessage(Interface.FIXED));
break;
case RESIZABLE:
player.send(new InterfaceRootMessage(Interface.RESIZABLE));
break;
}
/* Clear out all the current components if any exist */
components.clear();
/* Get the components for the display mode, and refresh each one */
List<ComponentType> types = ComponentType.getComponentTypes(mode);
for (ComponentType type : types) {
/* Create and refresh the component */
Component component = new Component(type);
component.refresh();
/* Register the component to the component mapping */
components.put(type, component);
}
}
public void openWindow(int id) {
Component window = components.get(ComponentType.getWindow(mode));
window.set(id).refresh();
}
public void openWindow(int id, ComponentListener listener) {
Component window = components.get(ComponentType.getWindow(mode));
window.set(id).setListener(listener).refresh();
}
public void closeWindow() {
Component window = components.get(ComponentType.getWindow(mode));
window.reset();
}
public Component getWindow() {
Component window = components.get(ComponentType.getWindow(mode));
return window;
}
public void openOverlay(int id) {
Component overlay = components.get(ComponentType.getOverlay(mode));
overlay.set(id).refresh();
}
public void closeOverlay() {
Component overlay = components.get(ComponentType.getOverlay(mode));
overlay.reset();
}
public void openChatbox(int id) {
Component chatbox = components.get(ComponentType.CHATBOX_OVERLAY);
chatbox.set(id).refresh();
}
public void openChatbox(int id, ComponentListener listener) {
Component chatbox = components.get(ComponentType.CHATBOX_OVERLAY);
chatbox.set(id).setListener(listener).refresh();
}
public Component getChatbox() {
return components.get(ComponentType.CHATBOX_OVERLAY);
}
public void closeChatbox() {
Component chatbox = components.get(ComponentType.CHATBOX_OVERLAY);
chatbox.reset();
}
public Component getAttackTab() {
return components.get(ComponentType.getAttackTab(mode));
}
public void openAttackTab(int id) {
Component tab = components.get(ComponentType.getAttackTab(mode));
tab.set(id).refresh();
}
public void openInventory(int id) {
Component tab = components.get(ComponentType.getInventoryTab(mode));
tab.set(id).refresh();
}
public void closeInventory() {
Component tab = components.get(ComponentType.getInventoryTab(mode));
tab.reset();
}
public Component getInventory() {
return components.get(ComponentType.getInventoryTab(mode));
}
public Component getComponent(int id) {
for (Component component : components.values()) {
if (component.currentId == id) {
return component;
}
}
return null;
}
public void resetAll() {
for (Component component : components.values()) {
if (component.type == ComponentType.ATTACK_TAB_FIXED || component.type == ComponentType.ATTACK_TAB_RESIZABLE) {
continue;
}
component.reset();
}
}
}