/*
 * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT).
 *
 * Copyright (c) JCThePants (www.jcwhatever.com)
 *
 * 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.jcwhatever.nucleus.views.menu;

import com.jcwhatever.nucleus.utils.materials.NamedMaterialData;
import com.jcwhatever.nucleus.utils.MetaKey;
import com.jcwhatever.nucleus.utils.PreCon;
import com.jcwhatever.nucleus.utils.text.TextUtils;

import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.material.MaterialData;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;

/**
 * A utility class to build {@link MenuItem}'s.
 */
public class MenuItemBuilder {

    private ItemStack _itemStack;
    private MaterialData _materialData;
    private Integer _amount;
    private String _title;
    private String _description;
    private Map<Object, Object> _meta;
    private List<Runnable> _onClick;

    /**
     * Constructor.
     *
     * @param itemStack  The {@link org.bukkit.inventory.ItemStack} that represents the menu item.
     */
    public MenuItemBuilder(ItemStack itemStack) {
        PreCon.notNull(itemStack);

        _itemStack = itemStack;
    }

    /**
     * Constructor.
     *
     * @param material  The item {@link org.bukkit.Material}.
     */
    public MenuItemBuilder(Material material) {
        PreCon.notNull(material);

        _materialData = new MaterialData(material);
    }

    /**
     * Constructor.
     *
     * @param materialData  The item {@link org.bukkit.material.MaterialData}.
     */
    public MenuItemBuilder(MaterialData materialData) {
        PreCon.notNull(materialData);

        _materialData = materialData.clone();
    }

    /**
     * Constructor.
     *
     * @param materialName  The name of the material.
     */
    public MenuItemBuilder(String materialName) {
        PreCon.notNullOrEmpty(materialName);

        _materialData = NamedMaterialData.get(materialName);
        if (_materialData == null)
            throw new RuntimeException(materialName + " is not a recognized material.");
    }

    /**
     * Set the menu item title.
     *
     * @param title  The title text.
     * @param args   Optional title format arguments.
     *
     * @return  Self for chaining.
     */
    public MenuItemBuilder title(String title, Object... args) {
        PreCon.notNull(title);

        _title = TextUtils.format(title, args);

        return this;
    }

    /**
     * Set the menu item description.
     *
     * @param description  The description text.
     * @param args         Optional description format arguments.
     *
     * @return  Self for chaining.
     */
    public MenuItemBuilder description(String description, Object... args) {
        PreCon.notNull(description);

        _description = TextUtils.format(description, args);

        return this;
    }

    /**
     * Set the amount.
     *
     * @param amount  The amount.
     *
     * @return  Self for chaining.
     */
    public MenuItemBuilder amount(int amount) {
        _amount = amount;

        return this;
    }

    /**
     * Add meta data to the menu item.
     *
     * @param key    The meta key.
     * @param value  The meta value.
     *
     * @param <T>  The meta value type.
     *
     * @return  Self for chaining.
     */
    public <T> MenuItemBuilder meta(MetaKey<T> key, T value) {
        PreCon.notNull(key);

        if (_meta == null) {
            _meta = new HashMap<>(7);
        }

        _meta.put(key, value);

        return this;
    }

    public MenuItemBuilder onClick(Runnable onClick) {
        PreCon.notNull(onClick);

        if (_onClick == null)
            _onClick = new ArrayList<>(3);

        _onClick.add(onClick);

        return this;
    }

    /**
     * Build and return a new {@Code MenuItem}.
     *
     * @param slot  The inventory slot the menu item will be placed in.
     */
    public MenuItem build(int slot) {

        if (_itemStack == null) {
            _itemStack = new ItemStack(_materialData.getItemType());
            _itemStack.setData(_materialData);
        }

        MenuItem item = createMenuItem(slot, _itemStack.clone(), _meta, _onClick);

        if (_amount != null)
            item.setAmount(_amount);

        if (_title != null)
            item.setTitle(_title);

        if (_description != null)
            item.setDescription(_description);

        return item;
    }

    protected MenuItem createMenuItem(int slot, ItemStack itemStack,
                                      @Nullable Map<Object, Object> meta,
                                      @Nullable List<Runnable> onClick) {

        return new MenuItem(slot, itemStack, meta, onClick);
    }
}

@@ -1263,16 +1263,160 @@
 .menu;%0A%0A
+import com.jcwhatever.nucleus.utils.items.ItemStackUtils;%0Aimport com.jcwhatever.nucleus.utils.items.serializer.InvalidItemStackStringException;%0A
 import c
@@ -3056,18 +3056,50 @@
 material
+ or serialized item stack string
 .%0A
-
      */%0A
@@ -3281,32 +3281,410 @@
 ialData == null)
+ %7B%0A            try %7B%0A                // try parsing serialized item stack%0A                ItemStack%5B%5D itemStacks = ItemStackUtils.parse(materialName);%0A                if (itemStacks != null && itemStacks.length == 1) %7B%0A                    _itemStack = itemStacks%5B0%5D;%0A                    return;%0A                %7D%0A%0A            %7D catch (InvalidItemStackStringException ignore) %7B%7D%0A
 %0A            thr
@@ -3757,16 +3757,26 @@
 ial.%22);%0A
+        %7D%0A
     %7D%0A%0A 

add MenuItemBuilder parses serialized item stack strings