PageableGUIParser.java

package it.fulminazzo.yagl.parsers;

import it.fulminazzo.yagl.contents.GUIContent;
import it.fulminazzo.yagl.guis.GUI;
import it.fulminazzo.yagl.guis.PageableGUI;
import it.fulminazzo.yagl.utils.ParserUtils;
import it.fulminazzo.fulmicollection.interfaces.functions.BiFunctionException;
import it.fulminazzo.fulmicollection.interfaces.functions.TriConsumer;
import it.fulminazzo.fulmicollection.objects.Refl;
import it.fulminazzo.fulmicollection.structures.tuples.Tuple;
import it.fulminazzo.yamlparser.configuration.ConfigurationSection;
import it.fulminazzo.yamlparser.configuration.IConfiguration;
import org.jetbrains.annotations.NotNull;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * A parser to serialize {@link PageableGUI}.
 */
@SuppressWarnings("DataFlowIssue")
public class PageableGUIParser extends TypedParser<PageableGUI> {
    private static final String[] IGNORE_FIELDS = new String[]{"type", "size"};

    /**
     * Instantiates a new Pageable gui parser.
     */
    public PageableGUIParser() {
        super(PageableGUI.class);
    }

    @Override
    protected BiFunctionException<IConfiguration, String, PageableGUI> getLoader() {
        return (c, s) -> {
            ConfigurationSection section = c.getConfigurationSection(s);
            if (section == null) return null;
            Integer size = section.getInteger("size");
            if (size == null) throw new IllegalArgumentException("'size' cannot be null");
            Integer pages = section.getInteger("pages");
            if (pages == null) throw new IllegalArgumentException("'pages' cannot be null");
            final PageableGUI gui = (PageableGUI) getObjectFromType(GUI.class, section, size);
            try {
                gui.setPages(pages);
            } catch (IllegalStateException ignored) {}
            final Refl<PageableGUI> refl = new Refl<>(gui);

            final String guiType = section.getString("gui-type");
            if (guiType == null) throw new IllegalArgumentException("'gui-type' cannot be null");
            section.set("type", guiType);

            final GUI templateGUI;
            try {
                templateGUI = c.get(s, GUI.class);
                templateGUI.variables().clear();
            } catch (Exception e) {
                String message = String.format("Cannot properly load template GUI for PageableGUI: %s", e.getMessage());
                throw new IllegalArgumentException(message);
            }
            refl.setFieldObject("templateGUI", templateGUI);

            ConfigurationSection previousPage = section.getConfigurationSection("previous_page");
            if (previousPage != null)
                gui.setPreviousPage(previousPage.getInteger("slot"),
                        previousPage.get("content", GUIContent.class));

            ConfigurationSection nextPage = section.getConfigurationSection("next_page");
            if (nextPage != null)
                gui.setNextPage(nextPage.getInteger("slot"),
                        nextPage.get("content", GUIContent.class));

            Map<?, ?> variables = section.get("variables", Map.class);
            if (variables != null) variables.forEach((k, v) -> {
                if (k != null && v != null) gui.setVariable(k.toString(), v.toString());
            });

            final ConfigurationSection pagesSection = section.getConfigurationSection("gui-pages");
            if (pagesSection != null) loadPages(section, pagesSection, gui, IGNORE_FIELDS);

            return gui;
        };
    }

    private void loadPages(final @NotNull ConfigurationSection guiSection,
                           final @NotNull ConfigurationSection pagesSection,
                           final @NotNull PageableGUI gui,
                           final String @NotNull ... ignoreFields) {
        final List<GUI> guiPages = new LinkedList<>();
        for (int i = 0; i < gui.pages(); i++) {
            final String path = String.valueOf(i);
            ConfigurationSection pageSection = pagesSection.getConfigurationSection(path);
            if (pageSection == null) guiPages.add(gui.getPage(i + 1));
            else {
                for (String s : ignoreFields) pageSection.set(s, guiSection.getObject(s));
                guiPages.add(pagesSection.get(path, GUI.class));
                for (String s : ignoreFields) pageSection.set(s, null);
            }
        }
        new Refl<>(gui).setFieldObject("pages", guiPages);
    }

    @Override
    protected TriConsumer<IConfiguration, String, PageableGUI> getDumper() {
        return (c, s, p) -> {
            c.set(s, null);
            if (p == null) return;
            Refl<PageableGUI> refl = new Refl<>(p);

            c.set(s, refl.getFieldObject("templateGUI"));
            ConfigurationSection section = c.getConfigurationSection(s);
            section.set("gui-type", section.getString("type"));
            section.set("type", ParserUtils.classToType(GUI.class, p.getClass()));
            section.set("size", p.size());
            section.set("pages", p.pages());

            Tuple<Integer, GUIContent> previousPage = refl.getFieldObject("previousPage");
            previousPage.ifPresent((i, g) -> {
                ConfigurationSection previousSection = section.createSection("previous_page");
                previousSection.set("slot", i);
                previousSection.set("content", g);
            });

            Tuple<Integer, GUIContent> nextPage = refl.getFieldObject("nextPage");
            nextPage.ifPresent((i, g) -> {
                ConfigurationSection nextSection = section.createSection("next_page");
                nextSection.set("slot", i);
                nextSection.set("content", g);
            });

            section.set("variables", p.variables());

            final ConfigurationSection pagesSection = section.createSection("gui-pages");
            dumpPages(pagesSection, p, IGNORE_FIELDS);
            if (pagesSection.getKeys().isEmpty()) section.set(pagesSection.getName(), null);
        };
    }

    private void dumpPages(final @NotNull ConfigurationSection pagesSection, final @NotNull PageableGUI gui,
                           final String @NotNull ... ignoreFields) {
        final List<GUI> guiPages = new Refl<>(gui).getFieldObject("pages");
        for (int i = 0; i < guiPages.size(); i++) {
            final GUI page = guiPages.get(i);
            final String path = String.valueOf(i);
            pagesSection.set(path, page);

            final ConfigurationSection pageSection = pagesSection.getConfigurationSection(path);

            for (String s : ignoreFields) pageSection.set(s, null);
            final Set<String> keys = pageSection.getKeys();
            for (String k : keys) {
                Object object = pageSection.getObject(k);
                if (object instanceof ConfigurationSection && ((ConfigurationSection) object).getKeys().isEmpty())
                    pageSection.set(k, null);
                else if (object instanceof List && ((List<?>) object).isEmpty())
                    pageSection.set(k, null);
            }

            if (pageSection.getKeys().isEmpty()) pagesSection.set(pageSection.getName(), null);
        }
    }
}