/*******************************************************************************
 * This file is part of ASkyBlock.
 *
 *     ASkyBlock is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     ASkyBlock is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with ASkyBlock.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package com.wasteofplastic.askyblock.panels;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;

import com.wasteofplastic.askyblock.ASkyBlock;
import com.wasteofplastic.askyblock.Settings;
import com.wasteofplastic.askyblock.events.MiniShopEvent;
import com.wasteofplastic.askyblock.events.MiniShopEvent.TransactionType;
import com.wasteofplastic.askyblock.util.Util;
import com.wasteofplastic.askyblock.util.VaultHelper;

import net.milkbowl.vault.economy.EconomyResponse;

/**
 * @author tastybento
 *         Provides a handy control panel and minishop
 */
public class ControlPanel implements Listener {

    private static YamlConfiguration miniShopFile;
    private static HashMap<Integer, MiniShopItem> store = new HashMap<Integer, MiniShopItem>();
    private static YamlConfiguration cpFile;
    private ASkyBlock plugin;
    private static boolean allowSelling;
    private static String defaultPanelName;

    /**
     * @param plugin - ASkyBlock plugin object
     */
    public ControlPanel(ASkyBlock plugin) {
        this.plugin = plugin;
        if (Settings.useEconomy) {
            loadShop();
        }
        loadControlPanel();
    }

    /**
     * Map of panel contents by name
     */
    private static HashMap<String, HashMap<Integer, CPItem>> panels = new HashMap<String, HashMap<Integer, CPItem>>();

    /**
     * Map of CP inventories by name
     */
    public static HashMap<String, Inventory> controlPanel = new HashMap<String, Inventory>();

    public static Inventory miniShop;

    // The first parameter, is the inventory owner. I make it null to let
    // everyone use it.
    // The second parameter, is the slots in a inventory. Must be a multiple of
    // 9. Can be up to 54.
    // The third parameter, is the inventory name. This will accept chat colors.

    /**
     * This loads the minishop from the minishop.yml file
     */
    public static void loadShop() {
        // The first parameter is the Material, then the durability (if wanted),
        // slot, descriptions
        // Minishop
        store.clear();
        miniShopFile = Util.loadYamlFile("minishop.yml");
        allowSelling = miniShopFile.getBoolean("config.allowselling", false);
        ConfigurationSection items = miniShopFile.getConfigurationSection("items");
        ASkyBlock plugin = ASkyBlock.getPlugin();
        if (items != null) {
            // Create the store
            // Get how many the store should be
            int size = items.getKeys(false).size() + 8;
            size -= (size % 9);
            miniShop = Bukkit.createInventory(null, size, plugin.myLocale().islandMiniShopTitle);
            // Run through items
            int slot = 0;
            for (String item : items.getKeys(false)) {
                try {
                    String m = items.getString(item + ".material");
                    Material material = Material.matchMaterial(m);
                    int quantity = items.getInt(item + ".quantity", 0);
                    String extra = items.getString(item + ".extra", "");
                    double price = items.getDouble(item + ".price", -1D);
                    double sellPrice = items.getDouble(item + ".sellprice", -1D);
                    if (!allowSelling) {
                        sellPrice = -1;
                    }
                    String description = ChatColor.translateAlternateColorCodes('&',items.getString(item + ".description",""));
                    MiniShopItem shopItem = new MiniShopItem(material, extra, slot, description, quantity, price, sellPrice);
                    store.put(slot, shopItem);
                    miniShop.setItem(slot, shopItem.getItem());
                    slot++;
                } catch (Exception e) {
                    plugin.getLogger().warning("Problem loading minishop item #" + slot);
                    plugin.getLogger().warning(e.getMessage());
                    e.printStackTrace();
                }
            }

        }
    }

    /**
     * This loads the control panel from the controlpanel.yml file
     */
    public static void loadControlPanel() {
        ASkyBlock plugin = ASkyBlock.getPlugin();
        // Map of known panel contents by name
        panels.clear();
        // Map of panel inventories by name
        controlPanel.clear();
        cpFile = Util.loadYamlFile("controlpanel.yml");
        ConfigurationSection controlPanels = cpFile.getRoot();
        if (controlPanels == null) {
            plugin.getLogger().severe("Controlpanel.yml is corrupted! Delete so it can be regenerated or fix!");
            return;
        }
        // Go through the yml file and create inventories and panel maps
        for (String panel : controlPanels.getKeys(false)) {
            // plugin.getLogger().info("DEBUG: Panel " + panel);
            ConfigurationSection panelConf = cpFile.getConfigurationSection(panel);
            if (panelConf != null) {
                // New panel map
                HashMap<Integer, CPItem> cp = new HashMap<Integer, CPItem>();
                String panelName = ChatColor.translateAlternateColorCodes('&', panelConf.getString("panelname", "Commands"));
                if (panel.equalsIgnoreCase("default")) {
                    defaultPanelName = panelName;
                }
                ConfigurationSection buttons = cpFile.getConfigurationSection(panel + ".buttons");
                if (buttons != null) {
                    // Get how many buttons can be in the CP
                    int size = buttons.getKeys(false).size() + 8;
                    size -= (size % 9);
                    // Add inventory to map of inventories
                    controlPanel.put(panelName, Bukkit.createInventory(null, size, panelName));
                    // Run through buttons
                    int slot = 0;
                    for (String item : buttons.getKeys(false)) {
                        try {
                            String m = buttons.getString(item + ".material", "BOOK");
                            // Split off damage
                            String[] icon = m.split(":");
                            Material material = Material.matchMaterial(icon[0]);
                            if (material == null) {
                                material = Material.PAPER;
                                plugin.getLogger().severe("Error in controlpanel.yml " + icon[0] + " is an unknown material, using paper.");
                            }
                            String description = ChatColor.translateAlternateColorCodes('&',buttons.getString(item + ".description", ""));
                            String command = buttons.getString(item + ".command", "").replace("[island]", Settings.ISLANDCOMMAND);
                            String nextSection = buttons.getString(item + ".nextsection", "");
                            ItemStack i = new ItemStack(material);
                            if (icon.length == 2) {
                                i.setDurability(Short.parseShort(icon[1]));
                            }
                            CPItem cpItem = new CPItem(i, description, command, nextSection);
                            cp.put(slot, cpItem);
                            controlPanel.get(panelName).setItem(slot, cpItem.getItem());
                            slot++;
                        } catch (Exception e) {
                            plugin.getLogger().warning("Problem loading control panel " + panel + " item #" + slot);
                            plugin.getLogger().warning(e.getMessage());
                            e.printStackTrace();
                        }
                    }
                    // Add overall control panel
                    panels.put(panelName, cp);
                }
            }
        }
    }

    @SuppressWarnings("deprecation")
    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true)
    public void onInventoryClick(InventoryClickEvent event) {
        Player player = (Player) event.getWhoClicked(); // The player that
        // clicked the item
        ItemStack clicked = event.getCurrentItem(); // The item that was clicked
        Inventory inventory = event.getInventory(); // The inventory that was clicked in
        if (inventory.getName() == null) {
            return;
        }
        // ASkyBlock plugin = ASkyBlock.getPlugin();
        int slot = event.getRawSlot();
        // Challenges
        if (inventory.getName().equals(plugin.myLocale(player.getUniqueId()).challengesguiTitle)) {
            event.setCancelled(true);
            if (event.getClick().equals(ClickType.SHIFT_RIGHT)) {
                inventory.clear();
                player.closeInventory();
                player.updateInventory();
                return;
            }
            if (event.getSlotType() == SlotType.OUTSIDE) {
                inventory.clear();
                player.closeInventory();
                return;
            }

            // Get the list of items in this inventory
            List<CPItem> challenges = plugin.getChallenges().getCP(player);
            if (challenges == null) {
                plugin.getLogger().warning("Player was accessing Challenge Inventory, but it had lost state - was server restarted?");
                inventory.clear();
                player.closeInventory();
                Util.runCommand(player, Settings.CHALLENGECOMMAND);
                return;
            }
            if (slot >= 0 && slot < challenges.size()) {
                CPItem item = challenges.get(slot);
                // Check that it is the top items that are being clicked on
                // These two should be identical because it is made before
                if (clicked.equals(item.getItem())) {
                    // Next section indicates the level of panel to open
                    if (item.getNextSection() != null) {
                        inventory.clear();
                        Inventory newInventory = plugin.getChallenges().challengePanel(player, item.getNextSection());
                        // Update inventory
                        if(player.getOpenInventory().getTopInventory() != null) {                        	
                        	if(inventory.equals(player.getOpenInventory().getTopInventory())) {
                        		if(inventory.getSize() == newInventory.getSize()) {
                        			inventory.setContents(newInventory.getContents());
                        			return;
                        		}
                        	}
                        }
                        // Open new Inventory if update is not possible
                        player.closeInventory();
                        player.openInventory(newInventory);
                        
                        
                    } else if (item.getCommand() != null) {
                        Util.runCommand(player, item.getCommand());
                        inventory.clear();                        
                        
                        // Update inventory
                        if(player.getOpenInventory().getTopInventory() != null) {
                        	if(inventory.equals(player.getOpenInventory().getTopInventory())) {
                        		Inventory newInventory = plugin.getChallenges().challengePanel(player);
                        		if(inventory.getSize() == newInventory.getSize()) {
                        			inventory.setContents(newInventory.getContents());
                        			return;
                        		}
                        	}
                        }
                        
                        // Open new Inventory if update is not possible
                        player.closeInventory();
                        Bukkit.getScheduler().runTask(plugin, () -> player.openInventory(plugin.getChallenges().challengePanel(player)));
                        
                        
                        
                    }
                }
            }
            return;
        }
        /*
         * Minishop section
         */
        if (miniShop != null && inventory.getName().equals(miniShop.getName())) {
            String message = "";
            event.setCancelled(true); // Don't let them pick it up
            if (!Settings.useEconomy || slot == -999) {
                player.closeInventory();
                return;
            }
            if (event.getClick().equals(ClickType.SHIFT_RIGHT)) {                    
                player.closeInventory();
                player.updateInventory();
                return;
            }
            if (store.containsKey(slot)) {
                // We have a winner!
                MiniShopItem item = store.get(slot);
                if (clicked.equals(item.getItem())) {
                    // Check what type of click - LEFT = BUY, RIGHT = sell
                    if (event.getClick().equals(ClickType.LEFT)) {
                        // Check if item is for sale
                        if (item.getPrice() > 0D) {
                            // Check they can afford it
                            if (!VaultHelper.econ.has(player, Settings.worldName, item.getPrice())) {
                                message = (plugin.myLocale().minishopYouCannotAfford).replace("[description]", item.getDescription());
                            } else {
                                EconomyResponse r = VaultHelper.econ.withdrawPlayer(player, Settings.worldName, item.getPrice());
                                if (r.transactionSuccess()) {
                                    message = plugin.myLocale().minishopYouBought.replace("[number]", Integer.toString(item.getQuantity()));
                                    message = message.replace("[description]", item.getDescription());
                                    message = message.replace("[price]", VaultHelper.econ.format(item.getPrice()));
                                    Map<Integer, ItemStack> items = player.getInventory().addItem(item.getItemClean());
                                    if (!items.isEmpty()) {
                                        for (ItemStack i : items.values()) {
                                            player.getWorld().dropItem(player.getLocation(), i);
                                        }
                                    }
                                    // Fire event
                                    MiniShopEvent shopEvent = new MiniShopEvent(player.getUniqueId(), item, TransactionType.BUY);
                                    plugin.getServer().getPluginManager().callEvent(shopEvent);
                                } else {
                                    message = (plugin.myLocale().minishopBuyProblem).replace("[description]", item.getDescription());
                                }
                            }
                        }
                    } else if (event.getClick().equals(ClickType.RIGHT) && allowSelling && item.getSellPrice() > 0D) {
                        // Check if they have the item
                        if (player.getInventory().containsAtLeast(item.getItemClean(), item.getQuantity())) {
                            player.getInventory().removeItem(item.getItemClean());
                            VaultHelper.econ.depositPlayer(player, Settings.worldName, item.getSellPrice());
                            message = plugin.myLocale().minishopYouSold.replace("[number]", Integer.toString(item.getQuantity()));
                            message = message.replace("[description]", item.getDescription());
                            message = message.replace("[price]", VaultHelper.econ.format(item.getSellPrice()));
                            // Fire event
                            MiniShopEvent shopEvent = new MiniShopEvent(player.getUniqueId(), item, TransactionType.SELL);
                            plugin.getServer().getPluginManager().callEvent(shopEvent);
                        } else {
                            message = (plugin.myLocale().minishopSellProblem).replace("[description]", item.getDescription());
                            ;
                        }
                    }
                    if (!message.isEmpty()) {
                        Util.sendMessage(player, message);
                    }
                }
            }
            return;
        }
        // Check control panels
        for (String panelName : controlPanel.keySet()) {
            if (inventory.getName().equals(panelName)) {
                event.setCancelled(true);
                if (slot == -999) {
                    player.closeInventory();
                    return;
                }
                if (event.getClick().equals(ClickType.SHIFT_RIGHT)) {                    
                    player.closeInventory();
                    player.updateInventory();
                    return;
                }
                HashMap<Integer, CPItem> thisPanel = panels.get(panelName);
                if (slot >= 0 && slot < thisPanel.size()) {
                    // Do something
                    String command = thisPanel.get(slot).getCommand();
                    String nextSection = ChatColor.translateAlternateColorCodes('&', thisPanel.get(slot).getNextSection());
                    if (!command.isEmpty()) {
                        player.closeInventory(); // Closes the inventory
                        event.setCancelled(true);
                        Util.runCommand(player, command);
                        return;
                    }
                    if (!nextSection.isEmpty()) {
                        player.closeInventory(); // Closes the inventory
                        Inventory next = controlPanel.get(nextSection);
                        player.openInventory(next);
                        event.setCancelled(true);
                        return;
                    }
                    player.closeInventory(); // Closes the inventory
                    event.setCancelled(true);
                    return;
                }
            }
        }
    }

    /**
     * @return the defaultPanelName
     */
    public static String getDefaultPanelName() {
        return defaultPanelName;
    }

}