GUIImpl.java
package it.fulminazzo.yagl.guis;
import it.fulminazzo.yagl.actions.BiGUIAction;
import it.fulminazzo.yagl.actions.GUIAction;
import it.fulminazzo.yagl.contents.GUIContent;
import it.fulminazzo.yagl.viewers.Viewer;
import it.fulminazzo.fulmicollection.objects.FieldEquable;
import it.fulminazzo.fulmicollection.objects.Refl;
import it.fulminazzo.fulmicollection.utils.ReflectionUtils;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* A basic implementation of {@link GUI}.
*/
abstract class GUIImpl extends FieldEquable implements GUI {
protected static final int MAX_SIZE = 54;
@Getter
protected @Nullable String title;
protected List<Contents> contents;
protected final @NotNull Set<Integer> movableSlots;
protected final Map<String, String> variables = new HashMap<>();
protected GUIAction clickOutsideAction;
protected GUIAction openGUIAction;
protected GUIAction closeGUIAction;
protected BiGUIAction changeGUIAction;
/**
* Instantiates a new Gui.
*/
GUIImpl() {
this.contents = new LinkedList<>();
this.movableSlots = new HashSet<>();
}
/**
* Instantiates a new Gui.
*
* @param size the size
*/
public GUIImpl(int size) {
if (size < 0 || size > MAX_SIZE) throw new IllegalArgumentException("GUIs size must be bound between 0 and 54");
this.contents = createContents(size, null);
this.movableSlots = new HashSet<>();
}
@Override
public void open(@NotNull Viewer viewer) {
final Class<?> guiUtils;
try {
guiUtils = ReflectionUtils.getClass("it.fulminazzo.yagl.GUIAdapter");
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Could not find GUIAdapter class. This function requires the 'gui:bukkit' module to be added");
}
new Refl<>(guiUtils).invokeMethod("openGUI", this, viewer);
}
@Override
public @NotNull GUI setTitle(@Nullable String title) {
this.title = title;
return this;
}
@Override
public int size() {
return this.contents.size();
}
@Override
public @NotNull GUI clear() {
Collections.fill(this.contents, null);
return this;
}
@Override
public @NotNull GUI setMovable(int slot, boolean movable) {
if (movable) this.movableSlots.add(slot);
else this.movableSlots.remove(slot);
return this;
}
@Override
public boolean isMovable(int slot) {
return this.movableSlots.contains(slot);
}
@Override
public @NotNull List<GUIContent> getContents(int slot) {
Contents contents = this.contents.get(slot);
if (contents == null) return new LinkedList<>();
return contents.getContents();
}
@Override
public @NotNull GUI addContent(GUIContent @NotNull ... contents) {
int j = 0;
for (int i = 0; i < contents.length; i++) {
j = addSingle(contents[i], j);
if (j >= size())
throw new IllegalArgumentException(String.format("Could not set content at index %s because contents are already full", i));
}
return this;
}
/**
* Tries to add the given content from the given index.
*
* @param content the content
* @param index the index
* @return the new index if it was successful, an index higher than {@link #size()} if failed
*/
protected int addSingle(final @NotNull GUIContent content, int index) {
for (; index < this.contents.size(); index++) {
Contents c = this.contents.get(index);
if (c == null) {
this.contents.set(index, new Contents(content));
break;
}
}
return index;
}
@Override
public @NotNull GUI setContents(int slot, GUIContent @NotNull ... contents) {
this.contents.set(slot, new Contents(contents));
return this;
}
@Override
public @NotNull GUI unsetContent(int slot) {
this.contents.set(slot, null);
return this;
}
@Override
public @NotNull List<GUIContent> getContents() {
List<GUIContent> list = new LinkedList<>();
for (Contents content : this.contents)
if (content != null)
list.addAll(Arrays.asList(content.contents));
return list;
}
@Override
public @NotNull GUI onClickOutside(@NotNull GUIAction action) {
this.clickOutsideAction = action;
return this;
}
@Override
public @NotNull Optional<GUIAction> clickOutsideAction() {
return Optional.ofNullable(this.clickOutsideAction);
}
@Override
public @NotNull GUI onOpenGUI(@NotNull GUIAction action) {
this.openGUIAction = action;
return this;
}
@Override
public @NotNull Optional<GUIAction> openGUIAction() {
return Optional.ofNullable(this.openGUIAction);
}
@Override
public @NotNull GUI onCloseGUI(@NotNull GUIAction action) {
this.closeGUIAction = action;
return this;
}
@Override
public @NotNull Optional<GUIAction> closeGUIAction() {
return Optional.ofNullable(this.closeGUIAction);
}
@Override
public @NotNull GUI onChangeGUI(@NotNull BiGUIAction action) {
this.changeGUIAction = action;
return this;
}
@Override
public @NotNull Optional<BiGUIAction> changeGUIAction() {
return Optional.ofNullable(this.changeGUIAction);
}
@Override
public @NotNull Map<String, String> variables() {
return this.variables;
}
/**
* Create a new list of the given size.
*
* @param size the size
* @param copyFrom if not null, copy the contents of this list in the resulting one
* @return the list
*/
protected @NotNull List<Contents> createContents(int size, final @Nullable List<Contents> copyFrom) {
List<Contents> contents = new LinkedList<>();
for (int i = 0; i < size; i++) contents.add(null);
if (copyFrom != null)
for (int i = 0; i < Math.min(copyFrom.size(), contents.size()); i++)
contents.set(i, copyFrom.get(i));
return contents;
}
/**
* A type to keep track of multiple {@link GUIContent} for one slot.
*/
public static class Contents {
private final GUIContent @NotNull [] contents;
/**
* Instantiates a new Contents.
*
* @param contents the contents
*/
protected Contents(final GUIContent @NotNull ... contents) {
this.contents = contents;
}
/**
* Gets contents.
*
* @return the contents
*/
public @NotNull List<GUIContent> getContents() {
return Arrays.asList(this.contents);
}
/**
* Copies the current object to a new one.
*
* @return the copy
*/
public @NotNull Contents copy() {
return new GUIImpl.Contents(Arrays.stream(this.contents)
.map(c -> c == null ? null : c.copy())
.toArray(GUIContent[]::new));
}
@Override
public boolean equals(Object o) {
if (o instanceof Contents) {
Contents c = (Contents) o;
if (this.contents.length != c.contents.length) return false;
for (int i = 0; i < this.contents.length; i++) {
GUIContent c1 = this.contents[i];
GUIContent c2 = c.contents[i];
if (!Objects.equals(c1, c2)) return false;
}
return true;
}
return false;
}
@Override
public int hashCode() {
int hash = Contents.class.hashCode();
for (GUIContent content : this.contents) {
hash *= 31;
hash += content == null ? 191 : content.hashCode();
}
return hash;
}
@Override
public @NotNull String toString() {
return Arrays.toString(this.contents);
}
}
}