001/*
002 * This file is part of Baritone.
003 *
004 * Baritone is free software: you can redistribute it and/or modify
005 * it under the terms of the GNU Lesser General Public License as published by
006 * the Free Software Foundation, either version 3 of the License, or
007 * (at your option) any later version.
008 *
009 * Baritone is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public License
015 * along with Baritone.  If not, see <https://www.gnu.org/licenses/>.
016 */
017
018package baritone.api.command.helpers;
019
020import baritone.api.command.argument.IArgConsumer;
021import baritone.api.command.exception.CommandException;
022import baritone.api.command.exception.CommandInvalidTypeException;
023import baritone.api.utils.Helper;
024
025import java.awt.*;
026import java.util.Arrays;
027import java.util.List;
028import java.util.function.Function;
029import net.minecraft.ChatFormatting;
030import net.minecraft.network.chat.ClickEvent;
031import net.minecraft.network.chat.Component;
032import net.minecraft.network.chat.HoverEvent;
033import net.minecraft.network.chat.MutableComponent;
034
035public class Paginator<E> implements Helper {
036
037    public final List<E> entries;
038    public int pageSize = 8;
039    public int page = 1;
040
041    public Paginator(List<E> entries) {
042        this.entries = entries;
043    }
044
045    public Paginator(E... entries) {
046        this.entries = Arrays.asList(entries);
047    }
048
049    public Paginator<E> setPageSize(int pageSize) {
050        this.pageSize = pageSize;
051        return this;
052    }
053
054    public int getMaxPage() {
055        return (entries.size() - 1) / pageSize + 1;
056    }
057
058    public boolean validPage(int page) {
059        return page > 0 && page <= getMaxPage();
060    }
061
062    public Paginator<E> skipPages(int pages) {
063        page += pages;
064        return this;
065    }
066
067    public void display(Function<E, Component> transform, String commandPrefix) {
068        int offset = (page - 1) * pageSize;
069        for (int i = offset; i < offset + pageSize; i++) {
070            if (i < entries.size()) {
071                logDirect(transform.apply(entries.get(i)));
072            } else {
073                logDirect("--", ChatFormatting.DARK_GRAY);
074            }
075        }
076        boolean hasPrevPage = commandPrefix != null && validPage(page - 1);
077        boolean hasNextPage = commandPrefix != null && validPage(page + 1);
078        MutableComponent prevPageComponent = Component.literal("<<");
079        if (hasPrevPage) {
080            prevPageComponent.setStyle(prevPageComponent.getStyle()
081                    .withClickEvent(new ClickEvent(
082                            ClickEvent.Action.RUN_COMMAND,
083                            String.format("%s %d", commandPrefix, page - 1)
084                    ))
085                    .withHoverEvent(new HoverEvent(
086                            HoverEvent.Action.SHOW_TEXT,
087                            Component.literal("Click to view previous page")
088                    )));
089        } else {
090            prevPageComponent.setStyle(prevPageComponent.getStyle().withColor(ChatFormatting.DARK_GRAY));
091        }
092        MutableComponent nextPageComponent = Component.literal(">>");
093        if (hasNextPage) {
094            nextPageComponent.setStyle(nextPageComponent.getStyle()
095                    .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("%s %d", commandPrefix, page + 1)))
096                    .withHoverEvent(new HoverEvent(
097                            HoverEvent.Action.SHOW_TEXT,
098                            Component.literal("Click to view next page")
099                    )));
100        } else {
101            nextPageComponent.setStyle(nextPageComponent.getStyle().withColor(ChatFormatting.DARK_GRAY));
102        }
103        MutableComponent pagerComponent = Component.literal("");
104        pagerComponent.setStyle(pagerComponent.getStyle().withColor(ChatFormatting.GRAY));
105        pagerComponent.append(prevPageComponent);
106        pagerComponent.append(" | ");
107        pagerComponent.append(nextPageComponent);
108        pagerComponent.append(String.format(" %d/%d", page, getMaxPage()));
109        logDirect(pagerComponent);
110    }
111
112    public void display(Function<E, Component> transform) {
113        display(transform, null);
114    }
115
116    public static <T> void paginate(IArgConsumer consumer, Paginator<T> pagi, Runnable pre, Function<T, Component> transform, String commandPrefix) throws CommandException {
117        int page = 1;
118        consumer.requireMax(1);
119        if (consumer.hasAny()) {
120            page = consumer.getAs(Integer.class);
121            if (!pagi.validPage(page)) {
122                throw new CommandInvalidTypeException(
123                        consumer.consumed(),
124                        String.format(
125                                "a valid page (1-%d)",
126                                pagi.getMaxPage()
127                        ),
128                        consumer.consumed().getValue()
129                );
130            }
131        }
132        pagi.skipPages(page - pagi.page);
133        if (pre != null) {
134            pre.run();
135        }
136        pagi.display(transform, commandPrefix);
137    }
138
139    public static <T> void paginate(IArgConsumer consumer, List<T> elems, Runnable pre, Function<T, Component> transform, String commandPrefix) throws CommandException {
140        paginate(consumer, new Paginator<>(elems), pre, transform, commandPrefix);
141    }
142
143    public static <T> void paginate(IArgConsumer consumer, T[] elems, Runnable pre, Function<T, Component> transform, String commandPrefix) throws CommandException {
144        paginate(consumer, Arrays.asList(elems), pre, transform, commandPrefix);
145    }
146
147    public static <T> void paginate(IArgConsumer consumer, Paginator<T> pagi, Function<T, Component> transform, String commandPrefix) throws CommandException {
148        paginate(consumer, pagi, null, transform, commandPrefix);
149    }
150
151    public static <T> void paginate(IArgConsumer consumer, List<T> elems, Function<T, Component> transform, String commandPrefix) throws CommandException {
152        paginate(consumer, new Paginator<>(elems), null, transform, commandPrefix);
153    }
154
155    public static <T> void paginate(IArgConsumer consumer, T[] elems, Function<T, Component> transform, String commandPrefix) throws CommandException {
156        paginate(consumer, Arrays.asList(elems), null, transform, commandPrefix);
157    }
158
159    public static <T> void paginate(IArgConsumer consumer, Paginator<T> pagi, Runnable pre, Function<T, Component> transform) throws CommandException {
160        paginate(consumer, pagi, pre, transform, null);
161    }
162
163    public static <T> void paginate(IArgConsumer consumer, List<T> elems, Runnable pre, Function<T, Component> transform) throws CommandException {
164        paginate(consumer, new Paginator<>(elems), pre, transform, null);
165    }
166
167    public static <T> void paginate(IArgConsumer consumer, T[] elems, Runnable pre, Function<T, Component> transform) throws CommandException {
168        paginate(consumer, Arrays.asList(elems), pre, transform, null);
169    }
170
171    public static <T> void paginate(IArgConsumer consumer, Paginator<T> pagi, Function<T, Component> transform) throws CommandException {
172        paginate(consumer, pagi, null, transform, null);
173    }
174
175    public static <T> void paginate(IArgConsumer consumer, List<T> elems, Function<T, Component> transform) throws CommandException {
176        paginate(consumer, new Paginator<>(elems), null, transform, null);
177    }
178
179    public static <T> void paginate(IArgConsumer consumer, T[] elems, Function<T, Component> transform) throws CommandException {
180        paginate(consumer, Arrays.asList(elems), null, transform, null);
181    }
182}