/*******************************************************************************
* Copyright 2014 Tobias Welther
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.gui;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import de.tobiyas.racesandclasses.RacesAndClasses;
import de.tobiyas.racesandclasses.APIs.LanguageAPI;
import de.tobiyas.racesandclasses.APIs.LevelAPI;
import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.AbstractHolderManager;
import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.AbstractTraitHolder;
import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.classes.ClassContainer;
import de.tobiyas.racesandclasses.datacontainer.traitholdercontainer.race.RaceContainer;
import de.tobiyas.racesandclasses.eventprocessing.events.holderevent.HolderPreSelectEvent;
import de.tobiyas.racesandclasses.eventprocessing.events.holderevent.classevent.PreClassSelectEvent;
import de.tobiyas.racesandclasses.eventprocessing.events.holderevent.raceevent.PreRaceSelectEvent;
import de.tobiyas.racesandclasses.playermanagement.player.RaCPlayerManager;
import de.tobiyas.racesandclasses.traitcontainer.interfaces.markerinterfaces.Trait;
import de.tobiyas.racesandclasses.translation.languages.Keys;
import de.tobiyas.util.formating.StringFormatUtils;
public class HolderInventory extends InventoryView{
/**
* The Number of holders given in the selection.
*/
protected int numberOfHolder;
/**
* The player that will select a holders
*/
private final Player player;
/**
* The inventory with the selectable Holders
*/
private final Inventory holderInventory;
/**
* The holdermanager to use.
*/
private final AbstractHolderManager holderManager;
/**
* Plugin to call stuff on like config
*/
private static final RacesAndClasses plugin = RacesAndClasses.getPlugin();
/**
* Generates an Inventory for the Player and the passed HolderManager
*
* @param player
* @param holderManager
*/
public HolderInventory(Player player, AbstractHolderManager holderManager) {
super();
this.player = player;
this.holderManager = holderManager;
this.numberOfHolder = 0;
int inventorySize = (int) (Math.ceil((holderManager.getAllHolderNames().size() / 9d)) + 1) * 9;
if(inventorySize < 35){
inventorySize = 36;
}
String name = LanguageAPI.translate(RaCPlayerManager.get().getPlayer(player), Keys.holder_selectiongui_header,
"holder", StringFormatUtils.firstCapitalRestLow(holderManager.getContainerTypeAsString()),
"player", player.getName());
if(name.length() > 32) name = name.substring(0, 32);
this.holderInventory = Bukkit.getServer().createInventory(player, inventorySize, name);
fillWithHolders();
}
/**
* Fills the inventory with items representing the holders.
*/
private void fillWithHolders(){
getTopInventory().clear();
Map<ItemStack, Integer> slotsToFill = new HashMap<ItemStack, Integer>();
for(String holderName : holderManager.listAllVisibleHolders()){
if(plugin.testingMode){
//Testing seems to not realize Bukkit is present. Method not found on ItemStack.
this.numberOfHolder++;
continue;
}
AbstractTraitHolder holder = holderManager.getHolderByName(holderName);
if(!hasPermission(holder, holderManager)) continue;
ItemStack item = generateForHolder(holder);
slotsToFill.put(item, holder.getGuiSlot());
this.numberOfHolder++;
}
//Sets the Slots as wanted.
Set<ItemStack> toAddAfter = new HashSet<ItemStack>();
for(Map.Entry<ItemStack,Integer> entry : slotsToFill.entrySet()){
ItemStack item = entry.getKey();
int slot = entry.getValue();
if(slot < 0 || slot > getTopInventory().getSize()){
toAddAfter.add(item);
continue;
}
getTopInventory().setItem(slot, item);
}
//Add the Rest items.
for(ItemStack item : toAddAfter){
getTopInventory().addItem(item);
}
}
/**
* Generates an ItemStack for the holder.
*
* @param holder to generate for
* @return the itemstack generated.
*/
private ItemStack generateForHolder(AbstractTraitHolder holder){
ItemStack item = holder.getHolderSelectionItem() != null
? holder.getHolderSelectionItem().clone()
: new ItemStack(Material.BOOK_AND_QUILL);
ItemMeta meta = item.getItemMeta();
boolean isEmptyTag = holder.getTag() == null || holder.getTag().equals("");
meta.setDisplayName(holder.getDisplayName() + " " + (isEmptyTag ? "[" + holder.getDisplayName() + "]" : holder.getTag()));
List<String> lore = meta.hasLore() ? meta.getLore() : new LinkedList<String>();
if(holder.hasHolderDescription()){
String description = holder.getHolderDescription();
String[] split = description.split("#n");
for(String desc : split){
lore.add(ChatColor.translateAlternateColorCodes('&', desc));
}
}
//Hide the Config part if wanted.
if(!holder.isHideConfigInGui()){
String healthString = getHealthString(holder);
if(healthString != null){
lore.add(ChatColor.AQUA + LanguageAPI.translate(RaCPlayerManager.get().getPlayer(player), Keys.health) + ": ");
lore.add(ChatColor.LIGHT_PURPLE + " " + healthString);
}
String manaString = getManaString(holder);
if(manaString != null){
lore.add(ChatColor.AQUA + LanguageAPI.translate(RaCPlayerManager.get().getPlayer(player), Keys.mana) + ": ");
lore.add(ChatColor.LIGHT_PURPLE + " " + manaString);
}
//add armor as lore
lore.add(ChatColor.AQUA + LanguageAPI.translate(RaCPlayerManager.get().getPlayer(player), Keys.armor) + ":");
if(holder.getArmorPerms().size() > 0){
lore.add(ChatColor.LIGHT_PURPLE + holder.getArmorString());
}else{
lore.add(ChatColor.LIGHT_PURPLE + "ANY");
}
//Add the Preconditions (if present).
lore.addAll(holder.getPreconditions().generateDescription(RaCPlayerManager.get().getPlayer(player)));
}
//Trait stuff below. Only when not hidden!
if(!holder.isHideTraitsInGui()){
lore.add(ChatColor.AQUA + LanguageAPI.translate(RaCPlayerManager.get().getPlayer(player), Keys.traits) + ":");
//add trait text as lore
for(Trait trait: holder.getVisibleTraits()){
lore.add(ChatColor.DARK_AQUA + trait.getDisplayName() + ": " );
String traitConfig = trait.getPrettyConfiguration();
String[] words = traitConfig.split(" ");
String currentLine = ChatColor.YELLOW + " -" + words[0];
for(int i = 1; i < words.length; i++){
String currentWord = words[i];
if(currentLine.length() + words.length + 1 > 29){
lore.add(currentLine);
currentLine = ChatColor.YELLOW + " " + currentWord;
}else{
currentLine += " " + currentWord;
}
}
if(currentLine.length() > 0){
lore.add(currentLine);
}
}
}
meta.setLore(lore);
item.setItemMeta(meta);
return item;
}
/**
* The Decimal formatter to use.
*/
private final DecimalFormat format = new DecimalFormat("0.0");
/**
* Returns a health String depending on the ContainerType
*/
private String getHealthString(AbstractTraitHolder holder) {
double max = holder.getMaxHealthMod(LevelAPI.getCurrentLevel(player));
return (max >= 0 ? "+":"") + format.format(max);
}
/**
* Returns a Mana String depending on the ContainerType
*/
private String getManaString(AbstractTraitHolder holder) {
double max = holder.getManaBonus(LevelAPI.getCurrentLevel(player));
return max == 0 ? null : ((max >= 0 ? "+":"") + format.format(max));
}
/**
* Checks if a player has the Permission for a holders
*
* @param holders to check
* @param manager the manager of the holders to check
* @return true if the player has access, false otherwise.
*/
private boolean hasPermission(AbstractTraitHolder holder, AbstractHolderManager manager) {
HolderPreSelectEvent event = null;
if(manager == plugin.getClassManager()){
event = new PreClassSelectEvent(player, (ClassContainer) holder, true, false);
}
if(manager == plugin.getRaceManager()){
event = new PreRaceSelectEvent(player, (RaceContainer) holder, true, false);
}
if(event == null) return true;
plugin.getServer().getPluginManager().callEvent(event);
return !event.isCancelled();
}
@Override
public Inventory getTopInventory() {
return holderInventory;
}
@Override
public Inventory getBottomInventory() {
return player.getInventory();
}
@Override
public HumanEntity getPlayer() {
return player;
}
@Override
public InventoryType getType() {
return InventoryType.CHEST;
}
/**
* @return the numberOfHolder
*/
public int getNumberOfHolder() {
return numberOfHolder;
}
public AbstractHolderManager getHolderManager() {
return holderManager;
}
}