com.jroossien.boxx.util.item.ItemParser.java Source code

Java tutorial

Introduction

Here is the source code for com.jroossien.boxx.util.item.ItemParser.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Rojoss <http://jroossien.com>
 * Copyright (c) 2016 contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.jroossien.boxx.util.item;

import com.jroossien.boxx.Boxx;
import com.jroossien.boxx.aliases.items.ItemData;
import com.jroossien.boxx.aliases.items.Items;
import com.jroossien.boxx.messages.Msg;
import com.jroossien.boxx.messages.Param;
import com.jroossien.boxx.options.SingleOption;
import com.jroossien.boxx.options.single.BoolO;
import com.jroossien.boxx.util.Parse;
import com.jroossien.boxx.util.Str;
import com.jroossien.boxx.util.Utils;
import org.apache.commons.lang.reflect.MethodUtils;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.inventory.ItemStack;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

public class ItemParser {

    private String string = null;
    private EItem item = null;

    private String error = null;

    /**
     * Parse the given string in to a item.
     *
     * @param string String with item format.
     * @param ignoreErrors If this is true it will continue parsing even if there are non breaking errors.
     */
    public ItemParser(String string, CommandSender sender, boolean ignoreErrors) {
        this.string = string;
        if (string == null || string.isEmpty()) {
            error = Msg.getString("itemparser.no-input");
            return;
        }

        List<String> sections = Str.splitQuotes(string, ' ', false);

        //Go through all the sections.
        for (int i = 0; i < sections.size(); i++) {
            String section = sections.get(i);

            //Get ItemData from first section
            if (i == 0) {
                ItemData item = Items.getItem(section);
                if (item == null) {
                    error = Msg.getString("itemparser.invalid-item", Param.P("input", section));
                    return;
                }
                this.item = new EItem(item.getType(), item.getData());
                continue;
            }

            //Set amount if it's a number
            Integer amount = Parse.Int(section);
            if (amount != null) {
                item.setAmount(amount);
                continue;
            }

            String[] split = section.split(":", 2);
            String key = split[0].toUpperCase().replace("_", "").replace(" ", "");
            String value = split.length > 1 ? split[1] : ""; //Allow key only

            //Try to parse ItemTag
            ItemTag tag = ItemTag.fromString(key);
            if (tag == null) {
                error = Msg.getString("parser.invalid-tag", Param.P("tag", key), Param.P("value", value),
                        Param.P("type", Msg.getString("itemparser.type")), Param.P("tags", Utils
                                .getAliasesString("parser.tag-entry", ItemTag.getTagsMap(item.getItemMeta()))));
                if (!ignoreErrors) {
                    return;
                }
                continue;
            }

            //Make sure the item tag can be used for the meta of the item.
            if (!ItemTag.getTags(item.getItemMeta()).contains(tag)) {
                error = Msg.getString("parser.unusable-tag", Param.P("tag", key),
                        Param.P("type", Msg.getString("itemparser.type")), Param.P("tags", Utils
                                .getAliasesString("parser.tag-entry", ItemTag.getTagsMap(item.getItemMeta()))));
                System.out.println(Msg.fromString(error).get());
                if (!ignoreErrors) {
                    return;
                }
                continue;
            }

            //Parse the value for the tag
            SingleOption option = (SingleOption) tag.getOption().clone();
            if (option instanceof BoolO && value.isEmpty()) {
                value = "true"; //Allow empty tags for booleans like 'glow' instead of 'glow:true'
            }
            if (!option.parse(sender, value)) {
                error = option.getError();
                if (!ignoreErrors) {
                    return;
                }
                continue;
            }

            //Apply the tag to the item
            if (tag.hasCallback()) {
                if (!tag.getCallback().onSet(sender, item, option)) {
                    error = Msg.getString("parser.tag-fail", Param.P("tag", key), Param.P("value", value));
                    if (!ignoreErrors) {
                        return;
                    }
                    continue;
                }
            } else {
                boolean success = false;
                try {
                    MethodUtils.invokeMethod(item, tag.setMethod(), option.getValue());
                    success = true;
                } catch (NoSuchMethodException e) {
                    error = Msg.getString("parser.missing-method", Param.P("tag", key), Param.P("value", value),
                            Param.P("method",
                                    tag.setMethod() + "(" + option.getValue().getClass().getSimpleName() + ")"));
                } catch (IllegalAccessException e) {
                    error = Msg.getString("parser.inaccessible-method", Param.P("tag", key),
                            Param.P("value", value), Param.P("method",
                                    tag.setMethod() + "(" + option.getValue().getClass().getSimpleName() + ")"));
                } catch (InvocationTargetException e) {
                    error = Msg.getString("parser.non-invokable-method", Param.P("tag", key),
                            Param.P("value", value), Param.P("method",
                                    tag.setMethod() + "(" + option.getValue().getClass().getSimpleName() + ")"));
                }
                if (!success && !ignoreErrors) {
                    return;
                }
            }
        }
    }

    /**
     * Parse the given item in to a string.
     *
     * @param itemStack item which needs to be parsed.
     */
    public ItemParser(ItemStack itemStack) {
        this(new EItem(itemStack));
    }

    public ItemParser(EItem item) {
        this.item = item;

        if (item == null) {
            return;
        }

        //Air can't have any meta.
        if (item.getType() == Material.AIR) {
            this.string = Items.getName(Material.AIR, (byte) 0);
            return;
        }

        List<String> sections = new ArrayList<>();

        sections.add(Items.getName(item.getData()).replaceAll(" ", ""));
        if (item.getAmount() > 1) {
            sections.add(Integer.toString(item.getAmount()));
        }

        for (ItemTag tag : ItemTag.getTags(item.getItemMeta())) {
            if (tag.hasCallback()) {
                String result = tag.getCallback().onGet(item);
                if (result == null || result.isEmpty()) {
                    continue;
                }
                if (!result.toLowerCase().contains(tag.getTag().toLowerCase() + ":")) {
                    result = Str.escapeWords(Str.escapeQuotes(result));
                } else {
                    result = Str.escapeQuotes(result);
                }
                sections.add(tag.getTag().toLowerCase() + ":" + result);
            } else {
                if (tag.getMethod() == null || tag.getMethod().isEmpty()
                        || tag.getMethod().equalsIgnoreCase("null")) {
                    continue;
                }
                try {
                    Object result = MethodUtils.invokeMethod(item, tag.getMethod(), new Class[0]);
                    if (result == null) {
                        continue;
                    }
                    SingleOption option = (SingleOption) tag.getOption().clone();
                    if (!option.parse(result)) {
                        Boxx.get().warn("Failed to parse entity data! [tag=" + tag.getTag() + " value="
                                + result.toString() + " error='" + option.getError() + "']");
                        continue;
                    }
                    if (option.getValue().equals(option.getDefault())) {
                        continue;
                    }
                    sections.add(tag.getTag().toLowerCase() + ":"
                            + Str.escapeWords(Str.escapeQuotes(option.serialize())));
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

        this.string = Str.implode(sections, " ");
    }

    /**
     * Get the parsed string.
     * Will return null if the parser failed.
     *
     * @return Parsed string with all meta and such.
     */
    public String getString() {
        return string;
    }

    /**
     * Get the parsed item.
     * Will return null if the parser failed.
     *
     * @return Parsed EItem with all meta and such.
     */
    public EItem getItem() {
        return item;
    }

    /**
     * Check if the parsing was successful or not.
     * If not you can call getError to get the error message.
     *
     * @return Whether or not the parsing was successful.
     */
    public boolean isValid() {
        return item != null && string != null && error == null;
    }

    /**
     * If the parsing wasn't successful this will return the error message.
     *
     * @return Error message if there is one otherwise an empty string.
     */
    public String getError() {
        return error;
    }
}