package org.black_ixx.bossshop.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.black_ixx.bossshop.BossShop;
import org.black_ixx.bossshop.lottery.LotteryHolder;
import org.black_ixx.bossshop.mail.MailManager;
import org.black_ixx.bossshop.managers.BuyItemHandler;
import org.black_ixx.bossshop.managers.ItemStackCreator;
import org.black_ixx.bossshop.managers.StringManager;
import org.black_ixx.bossshop.util.AttributeRemover;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;

import cc.util.bossshop.FBukkit;
import cc.util.bossshop.filemanager.AFileManager;

public class BSShop extends AFileManager{

    private static final Pattern PATTERN=Pattern.compile("[%]([^%]+)[%]");
    public final String mShopName;
    private String sign_text="[BossShop]";
    private String mDisplayname="[BossShop]";
    private boolean needPermToCreateSign=true;
    private boolean mValid=true;
    private boolean mSpecial=false;
    private int mInvSize=9;
    private int mTotalWeight=0;
    private final HashMap<Integer,BSBuy> mShopItems=new HashMap<Integer,BSBuy>();
    private final HashMap<Integer,ItemStack> mMenuItems=new HashMap<Integer,ItemStack>();
    private String mEnterMsg="";
    private String mLeaveMsg="";

    /**
     * 新建一个商店
     * @param fileName /shops/下的商店配置文件名字
     */
    public BSShop(BossShop pPlugin,String fileName,String shopName){
        super(pPlugin,"shops/"+fileName,"1.0");
        this.mShopName=shopName;
    }

    /**
     * 重载商店配置
     * @return 是否载入
     */
    @Override
    public boolean reloadConfig(){
        this.info(C("Console.StartReloadShop")+this.mShopName);
        if(!super.reloadConfig()) return false;
        this.mMenuItems.clear();
        this.mShopItems.clear();
        this.addDefaults();
        this.sign_text=this.mConfig.getString("signs.text");
        this.needPermToCreateSign=this.mConfig.getBoolean("signs.NeedPermissionToCreateSign");
        this.mSpecial=this.mConfig.getBoolean("ShopTypeSpecial",false);
        this.mValid=true;
        this.mDisplayname=StringManager.transform(this.mConfig.getString("DisplayName",""));
        this.mEnterMsg=StringManager.transform(this.mConfig.getString("EnterMessage","进入"+this.mDisplayname+"商店"));
        this.mLeaveMsg=StringManager.transform(this.mConfig.getString("LeaveMessage","离开"+this.mDisplayname+"商店"));
        this.loadItems();
        this.finishedAddingItems();
        this.saveConfig();
        return true;
    }

    private void addDefaultItem(String name,String rewardType,String priceType,Object reward,Object price,List<String> menuitem,String message,int loc,String permission){
        ConfigurationSection c=this.mConfig.getConfigurationSection("shop").createSection(name);
        c.set("RewardType",rewardType);
        c.set("PriceType",priceType);
        c.set("Price",price);
        c.set("Reward",reward);
        c.set("MenuItem",menuitem);
        c.set("Message",message);
        c.set("InventoryLocation",loc);
        c.set("ExtraPermission",permission);
    }

    @Override
    protected void addDefaults(){
        super.addDefaults();
        if(this.mConfig.get("ShopName")!=null) this.mConfig.set("ShopName",null);
        this.mConfig.addDefault("signs.text","[ExtraShop]");
        this.mConfig.addDefault("signs.NeedPermissionToCreateSign",false);
        if(this.mConfig.getConfigurationSection("shop")==null){
            this.mConfig.createSection("shop");
        }
    }

    public String getShopName(){
        return mShopName;
    }

    public String getDisplayName(){
        return mDisplayname;
    }

    public String getEnterMessage(){
        return this.mEnterMsg;
    }
    
    public String getLeaveMessage(){
        return this.mLeaveMsg;
    }
    
    public String getSignText(){
        return sign_text;
    }

    public boolean needPermToCreateSign(){
        return needPermToCreateSign;
    }

    public int getInventorySize(){
        return mInvSize;
    }

    public HashMap<Integer,BSBuy> getItems(){
        return mShopItems;
    }

    /**
     * 获取商店下一个可用的上架位置,从1开始,<=0为无位置
     */
    public int getNextAvailableLoc(){
        Set<Integer> tPos=this.getMenuItemSet();
        for(int i=0;i<81;i++){
            if(!tPos.contains(i)) return i+1;
        }
        return 0;
    }

    /**
     * 根据物品名(此为配置文件节点名,非显示的名字),获取商店物品
     * @param name 物品名
     * @return 如果不存在返回null
     */
    public BSBuy getShopItem(String name){
        for(BSBuy sbuy : this.mShopItems.values()){
            if(sbuy.getName().equalsIgnoreCase(name)) return sbuy;
        }
        return null;
    }

    public BSBuy getShopItem(int pos){
        return this.mShopItems.get(pos);
    }

    /**
     * 获取菜单物品的拷贝
     * @param pos
     * @return
     */
    public ItemStack getMenuItem(int pos){
        ItemStack menuItem=this.mMenuItems.get(pos);
        if(menuItem==null) return null;
        else return menuItem.clone();
    }

    /**
     * 获取商店物品位置Set集合的拷贝
     */
    public Set<Integer> getMenuItemSet(){
        Set<Integer> pos=new HashSet<Integer>();
        pos.addAll(this.mMenuItems.keySet());
        return pos;
    }

    /**
     * 添加物品到商店
     * @param buy
     * @param menu_item
     * @param manager
     */
    public void addShopItem(BSBuy buy,ItemStack menu_item){
        boolean need_reedit=false;
        if(menu_item.hasItemMeta()){
            ItemMeta meta=menu_item.getItemMeta();
            if(!need_reedit&&meta instanceof SkullMeta){
                SkullMeta skullMeta=(SkullMeta)meta;
                if(skullMeta.hasOwner()) need_reedit=PATTERN.matcher(skullMeta.getOwner()).find();
            }
            if(meta.hasDisplayName()){
                String st=buy.transformMessage(meta.getDisplayName());
                if(!need_reedit) need_reedit=PATTERN.matcher(st).find();
                meta.setDisplayName(st);
            }
            if(meta.hasLore()){
                List<String> tList=meta.getLore();
                List<String> l=new ArrayList<String>();
                for(String s : tList){
                    l.add(buy.transformMessage(s));
                    if(!need_reedit) need_reedit=PATTERN.matcher(s).find();
                }
                if(!FBukkit.isItemMetaEmpty(meta)) meta.setLore(l);
            }
            if(!FBukkit.isItemMetaEmpty(meta)) menu_item.setItemMeta(meta);
        }
        if(buy.hasLimit()||buy.hasBuyTime()||buy.hasPersonalLimit()) need_reedit=true;
        buy.setNeedEdit(need_reedit);
        menu_item=AttributeRemover.hideAttributes(menu_item,buy.getHideItemFlag());
        mShopItems.put(buy.getInventoryLocation(),buy);
        mMenuItems.put(buy.getInventoryLocation(),menu_item);
        this.mTotalWeight+=buy.getWeight()>0?buy.getWeight():0;
    }

    /**
     * 重新设置商店背包大小,在每次重载商店后调用
     */
    private void resetInventorySize(){
        int highest=0;
        for(Integer pos : mShopItems.keySet()){
            BSBuy b=mShopItems.get(pos);
            if(b!=null&&pos>highest){
                highest=pos;
            }
        }
        highest++;
        this.mInvSize=BSShop.getSuitableSize(highest);
    }

    public void finishedAddingItems(){
        this.resetInventorySize();
    }

    /**
     * 获取合适的背包大小
     */
    public static int getSuitableSize(int pSize){
        if(pSize>72) return 81;
        int m=pSize/9;
        if(m*9<pSize) pSize=(m+1)*9;
        else pSize=m*9;
        return pSize;
    }

    public int getTotalWeight(){
        return this.mTotalWeight;
    }
    
    /**
     * 为特定的玩家加载定制的背包
     * <p>
     * 外部勿直接调用该函数,请通过{@link BSShopManager#openShop(Player, BSShop)来打开商店}<br />
     * 所有的信息均存储在holder中
     * </p>
     * @param pPlayer 玩家
     */
    public void openInventory(Player pPlayer){
        if(!this.mValid) return;

        BSShopHolder holder=null;
        if(this.mSpecial) holder=new LotteryHolder((BossShop)this.mPlugin,pPlayer,this);
        else holder=new BSShopHolder((BossShop)this.mPlugin,pPlayer,this);
        Inventory inventory=Bukkit.createInventory(holder,this.mInvSize,this.mDisplayname);
        holder.setInventory(inventory);
        holder.updateInventory();
        pPlayer.openInventory(inventory);
    }

    /**
     * 为指定玩家更新指定的背包,如果商店已经无效,将会清空玩家背包并关闭
     * @param inv 指定的背包
     * @param player 指定的玩家
     */
    public void updateInventory(Inventory inv,Player player){
        if(!(inv.getHolder() instanceof BSShopHolder)) return;
        BSShopHolder tHolder=(BSShopHolder)inv.getHolder();
        tHolder.updateInventory();
    }

    /**
     * 为所有玩家更新打开此商店的背包,如果商店已经无效,将会清空玩家背包并关闭
     */
    public void updateAllInventory(){
        for(Player player : FBukkit.getOnlinePlayers()){
            Inventory inv=player.getOpenInventory().getTopInventory();
            if(inv.getHolder() instanceof BSShopHolder){
                BSShop shop=((BSShopHolder)inv.getHolder()).getShop();
                if(shop==this) this.updateInventory(inv,player);
            }
        }
    }

    /**
     * 检查商店是否特殊类型的商店
     */
    public boolean isShopSpecial(){
        return this.mSpecial;
    }
    
    /**
     * 检查商店是否合法,比如重载后文件不存在
     */
    public boolean isShopValid(){
        return this.mValid;
    }

    private void loadItems(){
        ConfigurationSection shop_sec=this.mConfig.getConfigurationSection("shop");
        for(String key : shop_sec.getKeys(false)){
            ConfigurationSection sec=shop_sec.getConfigurationSection(key);
            if(sec==null){
                this.mPlugin.severe("创建商品["+shop_sec.getName()+"]时发生了错误,文件:"+this.mShopName);
                continue;
            }
            List<String> menusec=sec.getStringList("MenuItem");
            if(menusec==null){
                this.mPlugin.severe("创建商品["+shop_sec.getName()+"]时发生了错误,菜单物品不存在");
                continue;
            }
            ItemStack menu=((BossShop)this.mPlugin).getManager(ItemStackCreator.class).createItemStackS(menusec,true);
            BSBuy items=((BossShop)this.mPlugin).getManager(BuyItemHandler.class).createBuyItem(this,sec);
            if(items==null) continue;
            if(items.hasOwner()){
                if(items.getLimit()==0){
                    this.removeItem(items.getName(),false);
                    shop_sec.set(key,null);
                    continue;
                }
                if(!items.isBuyTime()){
                    ((BossShop)this.mPlugin).getManager(MailManager.class).addMail(items,this.mPlugin.getLangManager().getNode("Mail.FromOutDateSale"));
                    shop_sec.set(key,null);
                    continue;
                }
            }
            this.addShopItem(items,menu);
        }
    }

    /**
     * 删除商店配置文件中的商品
     * @param pname 商品名字
     * @param update 是否保存并重载配置
     */
    public ConfigurationSection removeItem(String pname,boolean update){
        ConfigurationSection sec=this.mConfig.getConfigurationSection("shop."+pname);
        this.mConfig.set("shop."+pname,null);
        if(update) this.saveConfig();
        BSBuy tBuy=this.getShopItem(pname);
        if(tBuy!=null){
            this.mMenuItems.remove(tBuy.getInventoryLocation());
            this.mShopItems.remove(tBuy.getInventoryLocation());
            this.mTotalWeight-=tBuy.getWeight()>0?tBuy.getWeight():0;
        }
        return sec;
    }

    /**
     * 重新载入商店
     * @return
     */
    public boolean reloadShop(){
        if(!this.mFile.exists()||this.mFile.isDirectory()){
            warn(C("Console.ShopFileNotExist")+"["+this.mShopName+"]");
            this.mValid=false;
            this.mMenuItems.clear();
            this.mShopItems.clear();
            this.mConfig.set("shop",null);
            return false;
        }
        this.reloadConfig();
        return true;
    }

}
