# -*- coding: utf-8 -*-
import os
from item import *

class Generator(Exception):
    pass

class Generator():

    def __init__(self, list = []):
        self.wand = {"s":[],"a":[],"b":[],"c":[],"d":[]}
        self.passive = {"s":[],"a":[],"b":[],"c":[],"d":[]}
        self.armor = {"s":[],"a":[],"b":[],"c":[],"d":[]}
        self.weapon = {"s":[],"a":[],"b":[],"c":[],"d":[]}
        self.shard = {"s":[],"a":[],"b":[],"c":[],"d":[]}
        self.all = {"wand":self.wand, "passive":self.passive, "armor":self.armor, "weapon":self.weapon, "shard":self.shard}
        self.add(list)

    def add(self, l):
        if isinstance(l, list):
            for i,e in enumerate(l):
                if isinstance(e, list):
                    self.add(e)
                elif isinstance(e, Item):
                    self.sort(e)
                else:
                    raise Generator('Element in l[{0}] is not an Item'.format(i))
        elif isinstance(l, Item):
            self.sort(l)
        else:
            raise Generator("must be give a list of Items, an Item or a list with list of Items")

    def sort(self, e):
        if e.type == "wand":
            self.wand[e.rank.lower()].append(e)
        elif e.type == "armor":
            self.armor[e.rank.lower()].append(e)
        elif e.type == "weapon":
            self.weapon[e.rank.lower()].append(e)
        elif e.type == "passive":
            self.passive[e.rank.lower()].append(e)
        elif e.type == "shard":
            self.shard[e.rank.lower()].append(e)
        else:
            raise Generator("{} Item has no self.type (Itype) place for the generator".format(e))

    def make(self):
        for type in self.all:
            for rank in self.all[type]:
                self.paths(type, rank)
                for i,item in enumerate(self.all[type][rank]):
                    self.item(item, i)
                self.rank(type, rank)
            self.type(type)
        self.global_()

    def paths(self, type, rank):
        paths = []
        paths.append('../items_py/advancements/{0}/{1}'.format(type, rank))
        if type != "shard":
            paths.append('../items_py/functions/holder/{0}/{1}/times_appeared/rmv'.format(type, rank))
        paths.append('../items_py/functions/item_book/{0}/{1}'.format(type, rank))
        paths.append('../items_py/functions/give/{0}/all'.format(type))
        paths.append('../items_py/functions/mshop/display/{0}'.format(type))
        paths.append('../items_py/functions/mshop/buy/{0}/all'.format(type))
        paths.append('../items_py/functions/shop/display/{0}/all'.format(type))
        paths.append('../items_py/functions/shop/buy/{0}'.format(type))
        paths.append('../items_py/functions/rnd_shard_drop/all')
        paths.append('../items_py/functions/shard_break/all')
        paths.append('../items_py/predicates/in_inventory')
        paths.append('../items_py/predicates/selected')
        paths.append('../items_py/predicates/equipped')

        for p in paths:
            if not os.path.exists(p):
                os.makedirs(p)
                print("Directory ", p , " Created ")


# ========== Item part ============
    def item(self, item, i):
        if item.book:
            self.book_item(item, i)
        self.give_item(item)
        if item.type != "shard":
            self.holder_item(item)
        else:
            self.shard_drop(item)
        self.display_item(item)
        if not item.bought:
            self.mdisplay_item(item)
            self.mbuy_item(item)
        self.equipped_item(item)
        if item.type == "shard" and item.name_plain_().split("_")[0] != "small":
            self.shard_break(item)
        self.in_inventory(item)
        if item.type in ["weapon", "wand"]:
            self.selected(item)
        if item.type == "armor":
            self.item_equipped(item)

    def book_item(self, item, i):
        color = ',display:{color:'+str(item.color)+'}' if item.color != None else ''
        fpath = 'items_py:item_book/{0}/{1}/{2}'.format(item.type, item.rank, item.name_plain_())
        ppath = "items_py:{0}/{1}/{2}".format(item.type, item.rank, self.all[item.type][item.rank][i-1].name_plain_())
        if i == 0:
            ppath = "items_py:{0}/{1}/root".format(item.type, item.rank)


        t = open("template/item_book.json")
        data = t.read()
        t.close()

        dic = {
            "[name]"    : item.name.json('advancement').replace('"bold":true', '"bold":false').replace('"underlined":true', '"underlined":false').replace(']', ',{"text":"                                                   ","underlined":false}]'),
            "[lore]"    : item.lore.json('advancement'),
            "[item_id]" : item.id,
            "[model]"   : item.model,
            "[color]"   : color,
            "[nbt]"     : item.name_plain_(),
            "[fpath]"   : fpath,
            "[ppath]"   : ppath
            }
        for i in dic:
            data = data.replace(i, str(dic[i]))

        f = open('../items_py/advancements/{0}/{1}/{2}.json'.format(item.type, item.rank, item.name_plain_()),'w')
        f.write(data)
        f.close()

        f = open('../items_py/functions/item_book/{0}/{1}/{2}.mcfunction'.format(item.type, item.rank, item.name_plain_()),'w')
        f.write("advancement grant @a only items_py:{0}/{1}/root {2}".format(item.type, item.rank, item.name_plain_()))
        f.close()

    def give_item(self, item):
        g = open('../items_py/functions/give/{0}/all/{1}.mcfunction'.format(item.type, item.name_plain_()),'w')
        g.write('give @s '+item.id+item.data())
        g.close()

    def holder_item(self, item):
        h = open('../items_py/functions/holder/{0}/{1}/{2}.mcfunction'.format(item.type, item.rank, item.name_plain_()),'w')
        h.write("""
data merge entity @s {{HandItems:[{{id:{0},Count:1b,tag:{1}}},{{}}]}}\n
data merge entity @s {{DisabledSlots:4144703,ShowArms:1b,CustomNameVisible:1b,CustomName:{2}}}\n
tag @e[tag=ingame_items,limit=1] add {3}
scoreboard players add {3} times_appeared 1""".format(item.id, item.data(), item.name.json(), item.name_plain_()))
        h.close()

    def display_item(self, item):
        sd = open('../items_py/functions/shop/display/{0}/all/{1}.mcfunction'.format(item.type, item.name_plain_()),'w')
        if item.holder:
            sd.write("tag @e[tag=ingame_items] add {}\n".format(item.name_plain_()))
        sd.write("""
tag @s add {0}
tag @s add {2}
tag @s add {6}
scoreboard players set @s shop 0
data modify entity @e[tag=cost,sort=nearest,limit=1] CustomName set value '["",{{"text":"?","color":"dark_green"}},{{"text":"\\\\uF81d","color":"gray"}}]'

data modify entity @e[tag=name,sort=nearest,limit=1] CustomName set value {1}
data merge entity @e[type=item,tag=shop_d,sort=nearest,limit=1] {{Item:{{id:"{3}",tag:{{CustomModelData:{4},display:{{color:{5}}}}}}}}}
""".format(item.name_plain_(), item.name.json(), item.rank, item.id,item.model,item.color, item.type))
        sd.close()

    def mdisplay_item(self, item):
        sd = open('../items_py/functions/mshop/display/{0}/{1}.mcfunction'.format(item.type, item.name_plain_()),'w')
        sd.write("""
function items_py:shop/display/{0}/all/{1}
scoreboard players set @s shop {2}
data modify entity @e[tag=cost,sort=nearest,limit=1] CustomName set value '["",{{"text":"{2}","color":"dark_green"}},{{"text":"\\\\uF81d","color":"gray"}}]'
""".format(item.type, item.name_plain_(), item.price))
        sd.close()

    def mbuy_item(self, item):
        b = open('../items_py/functions/mshop/buy/{0}/all/{1}.mcfunction'.format(item.type, item.name_plain_()),'w')
        b.write("function items_py:holder/{0}/{1}/times_appeared/count_shop_active".format(item.type,item.rank))
        b.write("""
scoreboard players operation {0} times_appeared = min times_appeared
scoreboard players set #{0} shop 1
tag @s remove {0}

scoreboard players remove mcoins shop {1}
""".format(item.name_plain_(), item.price))

    def equipped_item(self, item):
        count = [item.custom_on, item.custom_off, item.give_tag].count(True)
        if count > 1:
            path = "../items_py/functions/equipped/{0}/{1}".format(item.type, item.name_plain_())
            if not os.path.exists(path):
                os.makedirs(path)

        if item.give_tag and item.custom_on:
            en = open('../items_py/functions/equipped/{0}/{1}/on.mcfunction'.format(item.type, item.name_plain_(), item.rank),'w')
            en.write('tag @s add {}\n'.format(item.name_plain_()))
            en.write("function items:{}/{}/on\n".format(item.type, item.name_plain_()))

        if item.give_tag and item.custom_off:
            ef = open('../items_py/functions/equipped/{0}/{1}/off.mcfunction'.format(item.type, item.name_plain_(), item.rank),'w')
            ef.write('tag @s remove {}\n'.format(item.name_plain_()))
            ef.write("function items:{}/{}/off\n".format(item.type, item.name_plain_()))

    def shard_drop(self, item):
        sd = open('../items_py/functions/rnd_shard_drop/all/{}.mcfunction'.format(item.name_plain_()),'w')
        sd.write('summon item ~ ~ ~ {{Item:{{id:"minecraft:amethyst_shard",Count:1b,tag:{0}}}}}'.format(item.data()))
        sd.close()

    def shard_break(self, item):
        s = open('../items_py/functions/shard_break/all/{}.mcfunction'.format(item.name_plain_()),'w')
        s.write('scoreboard players remove n_items items_generic 1\n')
        if item.name_plain_().split("_")[0] == "big":
            s.write('function items_py:give/shard/all/{}\n'.format(item.name_plain_().replace("big","medium")))
        else:
            s.write('function items_py:give/shard/all/{}\n'.format(item.name_plain_().replace("medium","small")))
        s.write('execute unless score n_items items_generic matches 0 run function items_py:shard_break/all/{0}'.format(item.name_plain_()))
        s.close()

    def in_inventory(self, item):
        p = open('../items_py/predicates/in_inventory/{0}.json'.format(item.name_plain_()),'w')
        p.write("""
{{
    "condition": "minecraft:entity_properties",
    "entity": "this",
    "predicate": {{
        "nbt": "{{Inventory:[{{tag:{{name:{0}}}}}]}}"
    }}
}}""".format(item.name_plain_()))
        p.close()

    def selected(self, item):
        p = open('../items_py/predicates/selected/{0}.json'.format(item.name_plain_()),'w')
        p.write("""
{
	"condition": "minecraft:entity_properties",
	"entity": "this",
	"predicate": {
		"equipment": {
			"mainhand": {
                "items": [
                    "minecraft:ITEM"
                ],
				"nbt": "{name:wand}"
			}
		}
	}
}""".replace( 'wand', item.name_plain_()).replace( 'ITEM', item.id ) )
        p.close()

    def item_equipped(self, item):
        p = open('../items_py/predicates/equipped/{0}.json'.format(item.name_plain_()),'w')
        p.write("""
{{
	"condition": "minecraft:entity_properties",
	"entity": "this",
	"predicate": {{
		"equipment": {{
			"{0}": {{
                "items": [
                    "minecraft:{1}"
                ],
				"nbt": "{{name:{2}}}"
			}}
		}}
	}}
}}
""".format(item.armor_piece, item.id, item.name_plain_()))
        p.close()

# ========== Rank part ============
    def rank(self, type, rank):
        self.book_rank_root(type, rank)
        self.give_rank(type, rank)
        self.mbuy_rank(type, rank)
        self.buy_rank(type, rank)
        if type != "shard":
            self.holder_rank(type, rank)

    def book_rank_root(self, type, rank):
        color = {"s":'dark_green', 'a':'dark_red', 'b':'dark_purple', 'c':'gold', 'd':'red'}
        model = {"s":6010, "a":6011, "b":6012, "c":6013, 'd':6014}
        fpath = 'items_py:item_book/{0}/{1}'.format(type, rank)
        ppath = 'items_py:{0}/root'.format(type)

        to_do = []
        for item in self.all[type][rank]:
            if item.book:
                to_do.append(item)

        criteria = ''
        for i,item in enumerate(to_do):
            criteria += '\n\t\t\t"{0}":{{"trigger": "minecraft:impossible"}}'.format(item.name_plain_())
            if i+1 < len(to_do):
                criteria += ','

        t = open("template/rank_root_book.json")
        data = t.read()
        t.close()

        dic = {
            "[rank]"        : rank.upper(),
            "[color]"       : color[rank],
            "[model]"       : model[rank],
            "[criteria]"    : criteria,
            "[fpath]"       : fpath,
            "[ppath]"       : ppath
            }
        for i in dic:
            data = data.replace(i, str(dic[i]))

        f = open("../items_py/advancements/{0}/{1}/root.json".format(type, rank),'w')
        f.write(data)
        f.close()

        f = open('../items_py/functions/item_book/{0}/{1}.mcfunction'.format(type, rank),'w')
        f.write("advancement grant @a only items_py:{0}/root {0}_all_{1}".format(type, rank))
        f.close()

    def give_rank(self, type, rank):
        g = open('../items_py/functions/give/{0}/{1}.mcfunction'.format(type, rank),'w')
        for item in self.all[type][rank]:
            g.write("function items_py:give/{0}/all/{1}\n".format(type, item.name_plain_()))
        g.close()

    def buy_rank(self, type, rank):
        b = open('../items_py/functions/shop/buy/{0}/{1}.mcfunction'.format(type, rank),'w')
        for item in self.all[type][rank]:
            if (item.holder == True) or (type == 'shard'):
                b.write("execute if entity @s[tag={1}] as @p run function items_py:give/{0}/all/{1}\n".format(type, item.name_plain_()))
            if type == 'shard':
                b.write("tag @s remove {}\n".format(item.name_plain_()))
        b.close()

    def mbuy_rank(self, type, rank):
        b = open('../items_py/functions/mshop/buy/{0}/{1}.mcfunction'.format(type, rank),'w')
        for item in self.all[type][rank]:
            if not item.bought:
                b.write("execute if entity @s[tag={1}] run function items_py:mshop/buy/{0}/all/{1}\n".format(type, item.name_plain_()))
        b.write("tag @s remove {}".format(rank))
        b.close()

    def holder_rank(self, type, rank):
        holder_pre = "../items_py/functions/holder/{0}/{1}/".format(type, rank)
        r       = open(holder_pre + '0_random.mcfunction', 'w')
        g       = open(holder_pre + '1_rmv_ingame.mcfunction', 'w')
        cnt     = open(holder_pre + 'times_appeared/count.mcfunction', 'w')
        rmv     = open(holder_pre + 'times_appeared/rmv.mcfunction', 'w')
        cnt_s   = open(holder_pre + 'times_appeared/count_shop_active.mcfunction', 'w')
        rmv_s   = open(holder_pre + 'times_appeared/rmv_shop_active.mcfunction', 'w')
        rmv_t   = open(holder_pre + '2_rmv_times_appeared.mcfunction', 'w')
        b       = open(holder_pre + '3_rmv_not_bought.mcfunction', 'w')
        c       = open(holder_pre + '4_choose.mcfunction', 'w')

        num = 0
        for item in self.all[type][rank]:
            if item.holder:
                num += 1

    # ======= Main (0_random) =========
        r.write("""
scoreboard players set max_rand items_generic {0}
function items_py:holder/random

function items_py:holder/{1}/{2}/1_rmv_ingame
function items_py:holder/{1}/{2}/2_rmv_times_appeared
execute if score active shop matches 1 run function items_py:holder/{1}/{2}/3_rmv_not_bought

execute as @e[sort=random,limit=1,tag=rand_item] run function items_py:holder/{1}/{2}/4_choose
kill @e[tag=rand_item]

execute unless predicate items:selected/barrier run tag @s add filled
execute if predicate items:selected/barrier run tag @s add no_{2}
execute if predicate items:selected/barrier run tag @s remove {3}""".format(num, type, rank, rank.upper()))
        r.close()

    # ======= 1_rmv_ingame =========
        num_ = num
        for item in self.all[type][rank]:
            if item.holder:
                g.write('execute if entity @e[tag=ingame_items,tag={0}] run kill @e[tag={1},tag=rand_item]\n'.format(item.name_plain_(), num_))
                num_ -= 1
        g.close()

    # ======= 2_rmv_times_appeared =========
    # Remove Times appeared
        rmv_t.write("""
execute if score active shop matches 0 run function items_py:holder/{0}/{1}/count
execute if score active shop matches 0 run function items_py:holder/{0}/{1}/rmv
execute if score active shop matches 1 run function items_py:holder/{0}/{1}/count_shop_active
execute if score active shop matches 1 run function items_py:holder/{0}/{1}/rmv_shop_active
""".format(type, rank))
        rmv_t.close()

    # Count
        first = True
        for item in self.all[type][rank]:
            if item.holder:
                if first:
                    cnt.write("scoreboard players operation min times_appeared = {} times_appeared\n".format(item.name_plain_()))
                    first = False
                else:
                    cnt.write("execute if score {0} times_appeared < min times_appeared run scoreboard players operation min times_appeared = {0} times_appeared\n".format(item.name_plain_()))
        cnt.close()

    # Count shop active
        cnt_s.write("scoreboard players set min times_appeared 0\n")
        for item in self.all[type][rank]:
            if item.holder:
                cnt_s.write("""
execute if score #{0} shop matches 1 if score min times_appeared matches -1 run scoreboard players operation min times_appeared = {0} times_appeared
execute if score #{0} shop matches 1 if score {0} times_appeared < min times_appeared run scoreboard players operation min times_appeared = {0} times_appeared
""".format(item.name_plain_()))
        cnt_s.write("execute if score min times_appeared matches -1 run scoreboard players set min times_appeared 0")
        cnt_s.close()

    # Remove
        num_ = num
        for item in self.all[type][rank]:
            if item.holder:
                rmv.write("function items_py:holedr/{0}/{1}/times_appeared/rmv/{2}_{3}\n".format(type, rank, num_, item.name_plain_()))
                num_ -= 1
        rmv.close()

    # Remove shop active
        num_ = num
        for item in self.all[type][rank]:
            if item.holder:
                rmv_s.write("execute if score #{3} shop matches 1 run function items_py:holedr/{0}/{1}/times_appeared/rmv/{2}_{3}\n".format(type, rank, num_, item.name_plain_()))
                num_ -= 1
        rmv_s.close()

    # Times appeared item specific
        num_ = num
        for item in self.all[type][rank]:
            if item.holder:
                ta = open('../items_py/functions/holder/{0}/{1}/times_appeared/rmv/{2}_{3}.mcfunction'.format(type, rank, num_, item.name_plain_()),'w')
                ta.write("""
scoreboard players operation tmp times_appeared = {} times_appeared
scoreboard players operation tmp times_appeared -= min times_appeared
scoreboard players operation tmp times_appeared *= factor times_appeared
function rng:percentage
execute if score tmp times_appeared > out rng run kill @e[tag={},tag=rand_item]
""".format(item.name_plain_(),num_))
                ta.close()
                num_ -= 1

    # ======= 3_rmv_not_bought =========
        num_ = num
        for item in self.all[type][rank]:
            if item.holder:
                b.write('execute if score #{0} shop matches 0 run kill @e[tag={1},tag=rand_item]\n'.format(item.name_plain_(), num_))
                num_ -= 1
        b.close()

    # ======= 4_choose =========
        num_ = num
        for item in self.all[type][rank]:
            if item.holder:
                c.write('execute if entity @s[tag={0}] as @e[tag=holder,distance=0] run function items_py:holder/{1}/{2}/{3}\n'.format(num_, type, rank, item.name_plain_()))
                num_ -= 1
        c.close()


# ========== Type part ============
    def type(self, type):
        self.book_type_root(type)
        self.give_type(type)
        self.mbuy_type(type)
        self.buy_type(type)
        if type != "shard":
            self.holder_type(type)
        self.type_shop_display(type)

    def book_type_root(self, type):
        model = {"wand":1401, "passive":2103, "armor":0, "weapon":3504, "shard":0}
        background = {"wand":"cyan_wool", "passive":"stripped_spruce_log", "armor":"iron_block", "weapon":"red_wool", "shard":"amethyst_block"}
        id = {"wand":"carrot_on_a_stick", "passive":"stick", "armor":"iron_chestplate", "weapon":"wooden_sword", "shard":"amethyst_shard"}

        t = open("template/type_root_book.json")
        data = t.read()
        t.close()

        dic = {
            "[type]"        : type,
            "[item_id]"     : id[type],
            "[model]"       : model[type],
            "[background]"  : background[type] + ".png"
            }
        for i in dic:
            data = data.replace(i, str(dic[i]))

        f = open('../items_py/advancements/{0}/root.json'.format(type),'w')
        f.write(data)
        f.close()

    def give_type(self, type):
        f = open('../items_py/functions/give/{0}.mcfunction'.format(type),'w')
        for rank in self.all[type]:
            f.write("function items_py:give/{0}/{1}\n".format(type, rank))
        f.close()

    def buy_type(self, type):
        b = open('../items_py/functions/shop/buy/{0}.mcfunction'.format(type),'w')
        for rank in self.all[type]:
            b.write("execute if entity @s[tag={1}] run function items_py:shop/buy/{0}/{1}\n".format(type, rank))
        b.close()

    def mbuy_type(self, type):
        b = open('../items_py/functions/mshop/buy/{0}.mcfunction'.format(type),'w')
        for rank in self.all[type]:
            b.write("execute if entity @s[tag={1}] run function items_py:mshop/buy/{0}/{1}\n".format(type, rank))
        b.write("tag @s remove {}".format(type))
        b.close()

    def holder_type(self, type):
        f = open('../items_py/functions/holder/{0}/rank.mcfunction'.format(type),'w')
        for rank in self.all[type]:
            f.write('\nexecute if entity @s[tag={0}] run function items_py:holder/{1}/{2}/0_random'.format(rank.upper(), type, rank))
        f.close()

    def type_shop_display(self,type):
        to_display = 0
        for rank in self.all[type]:
            for item in self.all[type][rank]:
                if (item.holder == True) or (type == 'shard'):
                    to_display +=1

        dpr = open('../items_py/functions/shop/display/{}.mcfunction'.format(type),'w')
        dpr.write("""
scoreboard players set min rng 1
scoreboard players set max rng {}
function rng:interval
scoreboard players operation choose shop = out rng

scoreboard players set choose_loop shop 0
function items_py:shop/display/{}/random
""".format(to_display, type))
        if type == 'shard':
            dpr.write("\ntag @s add restock")
        dpr.close()

        dr = open('../items_py/functions/shop/display/{}/random.mcfunction'.format(type),'w')
        to_display_ = to_display
        for rank in self.all[type]:
            for item in self.all[type][rank]:
                if item.holder:
                    dr.write("""
execute if score choose shop matches {0} if score #{1} shop matches 0 run scoreboard players remove choose shop 1
execute if score choose shop matches {0} if entity @e[tag=ingame_items,tag={1}] run scoreboard players remove choose shop 1\n""".format(to_display_, item.name_plain_()))
                if item.holder or (type == 'shard'):
                    dr.write("execute if score choose shop matches {} run function items_py:shop/display/{}/all/{}\n".format(to_display_, type, item.name_plain_()))
                    to_display_ -= 1

        if type != 'shard':
            dr.write("# --- { Loop and guard }---\n")
            dr.write("execute if score choose shop matches 0 if score choose_loop shop matches 0 run function items_py:shop/display/{}/iterate_once\n".format(type))
            dr.close()

            it = open('../items_py/functions/shop/display/{}/iterate_once.mcfunction'.format(type),'w')
            it.write("scoreboard players set choose_loop shop 1\n")
            it.write("scoreboard players set choose shop {}\n".format(to_display))
            it.write("function items_py:shop/display/{}/random".format(type))
            it.close()

# ========== Global part ============
    def global_(self):
        # mshop
        self.mbuy()
        self.mshop_display()
        # shop
        self.buy()

        self.give_all()
        self.holder_random()
        self.equipped()
        self.set_calc()
        self.ingame_items()
        self.shop_init()
        self.times_appeared_init()
        self.mshop_n_buy()
        self.rnd_shard_drop()
        self.shards_break()

    def give_all(self):
        f = open('../items_py/functions/give.mcfunction','w')
        for type in self.all:
            f.write("function items_py:give/{0}\n".format(type))
        f.close()

    def buy(self):
        b = open('../items_py/functions/shop/buy.mcfunction','w')
        for type in self.all:
            b.write("execute if entity @s[tag={0}] run function items_py:shop/buy/{0}\n".format(type))
        b.write("execute if entity @s[tag=food] run function items:shop/buy/food\n".format(type))
        b.write("execute if entity @s[tag=potion] run function items:shop/buy/potion\n".format(type))
        b.write("execute if entity @s[tag=meta_coin] run scoreboard players add mcoins shop 1\n".format(type))
        b.close()

    def mbuy(self):
        b = open('../items_py/functions/mshop/buy.mcfunction','w')
        for type in self.all:
            b.write("execute if entity @s[tag={0}] run function items_py:mshop/buy/{0}\n".format(type))
        b.write("function items:shop/display_sold_out\n")
        b.close()

    def mshop_display(self):
        to_display = 0
        for type in self.all:
            for rank in self.all[type]:
                for item in self.all[type][rank]:
                    if not item.bought:
                        to_display +=1

        dpr = open('../items_py/functions/mshop/display.mcfunction','w')
        dpr.write("""
scoreboard players set min rng 1
scoreboard players set max rng {}
function rng:interval
scoreboard players operation choose shop = out rng

scoreboard players set choose_loop shop 0

function items_py:mshop/can_buy_n

execute if score can_buy_n shop matches 1.. run function items_py:mshop/display/random
""".format(to_display))
        dpr.close()

        dr = open('../items_py/functions/mshop/display/random.mcfunction','w')
        to_display_ = to_display
        for type in self.all:
            dr.write('\n# ------{ ' + type.upper() + ' }------\n')
            for rank in self.all[type]:
                for item in self.all[type][rank]:
                    if not item.bought:
                        dr.write("""
execute if score choose shop matches {2} if score #{0} shop matches 1 run scoreboard players remove choose shop 1
execute if score choose shop matches {2} if entity @e[tag={0},tag=shop_d] run scoreboard players remove choose shop 1
execute if score choose shop matches {2} run function items_py:mshop/display/{1}/{0}
""".format(item.name_plain_(), type, to_display_))
                        to_display_ -= 1

        dr.write("# --- { Loop and guard }---\n")
        dr.write("execute if score choose shop matches 0 if score choose_loop shop matches 0 run function items_py:mshop/display/iterate_once\n")
        dr.close()

        it = open('../items_py/functions/mshop/display/iterate_once.mcfunction','w')
        it.write("scoreboard players set choose_loop shop 1\n")
        it.write("scoreboard players set choose shop {}\n".format(to_display))
        it.write("function items_py:mshop/display/random")
        it.close()

    def holder_random(self):
        r = open('../items_py/functions/holder/random.mcfunction','w')
        r.write('kill @e[tag=rand_item]')
        max = 0
        for type in self.all.values():
            for rank in type.values():
                if len(rank) > max:
                    max = len(rank) + 1
        for i in range(max):
            r.write('\nexecute if score max_rand items_generic matches {0}.. run summon marker 1 47 6 {{Tags:["rand_item","{0}"]}}'.format(i+1))
        r.close()

    def equipped(self):
        e = open('../items_py/functions/equipped.mcfunction','w')
        for type in self.all:
            e.write('\n# ------{ ' + type.upper() + ' }------\n')
            for rank in self.all[type]:
                for item in self.all[type][rank]:
                    name_plain_ = item.name_plain_()

                    condition3 = 'if predicate items_py:in_inventory/{}'.format(name_plain_)
                    if item.type == "armor":
                        condition3 = condition3.replace('in_inventory','equipped')
                    elif item.type in ["weapon", "wand"]:
                        condition3 = condition3.replace('in_inventory','selected')
                    condition1 = condition3 + ' if entity @s[tag=!{}]'.format(name_plain_)
                    condition2 = condition3.replace('if', 'unless') + ' if entity @s[tag={}]'.format(name_plain_)

                    if item.give_tag:
                        if item.custom_on:
                            e.write("execute {} run function items_py:equipped/{}/{}/on\n".format(condition1, item.type, name_plain_))
                        else:
                            e.write("execute {} run tag @s add {}\n".format(condition1, name_plain_))

                        if item.custom_off:
                            e.write("execute {} run function items_py:equipped/{}/{}/off\n".format(condition2, item.type, name_plain_))
                        else:
                            e.write("execute {} run tag @s remove {}\n".format(condition2, name_plain_))
                    else:
                        if item.custom_on:
                            e.write("execute {} run function items:{}/{}/on\n".format(condition3, item.type, name_plain_))
                        if item.custom_off:
                            e.write("execute {} run function items:{}/{}/off\n".format(condition3, item.type, name_plain_))
        e.close()

    def set_calc(self):
        e = open('../items_py/functions/set_calc.mcfunction','w')
        for type in self.all:
            for rank in self.all[type]:
                for item in self.all[type][rank]:
                    if item.set != None:
                        name_plain_ = item.name_plain_()
                        cmd = "execute if predicate items_py:in_inventory/{} run scoreboard players add @s {} 1\n".format(name_plain_, item.set)
                        if item.type == "armor":
                            cmd = cmd.replace('in_inventory','equipped')
                        e.write(cmd)
        e.close()

    def ingame_items(self):
        i = open('../items_py/functions/ingame_items.mcfunction','w')
        i.write("kill @e[type=marker,tag=ingame_items]\n")
        i.write('summon marker ~ ~ ~ {Tags:["ingame_items","unspellable"]}\n')
        for type in self.all:
            i.write('\n# ------{ ' + type.upper() + ' }------\n')
            for rank in self.all[type]:
                for item in self.all[type][rank]:
                    if item.type != 'shard':
                        i.write("execute as @a if predicate items_py:in_inventory/{0} run tag @e[tag=ingame_items,limit=1] add {0}\n".format(item.name_plain_()))
        i.close()

    def shop_init(self):
        si = open('../items_py/functions/mshop/init.mcfunction','w')
        for type in self.all:
            si.write('\n# ------{ ' + type.upper() + ' }------\n')
            for rank in self.all[type]:
                for item in self.all[type][rank]:
                # Shop Init
                    if item.bought:
                        si.write("scoreboard players set #{0} shop 1\n".format(item.name_plain_()))
                    else:
                        si.write("scoreboard players operation #{0} shop = #{0} shop\n".format(item.name_plain_()))
        si.close()

    def times_appeared_init(self):
        ti = open('../items_py/functions/times_appeared_init.mcfunction','w')
        for type in self.all:
            ti.write('\n# ------{ ' + type.upper() + ' }------\n')
            for rank in self.all[type]:
                for item in self.all[type][rank]:
                    if item.holder:
                        ti.write("scoreboard players set {0} times_appeared 0\n".format(item.name_plain_()))
        ti.close()

    def mshop_n_buy(self):
        nb = open('../items_py/functions/mshop/can_buy_n.mcfunction','w')
        nb.write("scoreboard players set can_buy_n shop 0\n")
        for type in self.all:
            nb.write('\n# ------{ ' + type.upper() + ' }------\n')
            for rank in self.all[type]:
                for item in self.all[type][rank]:
                    if not item.bought:
                        nb.write("execute if score #{} shop matches 0 run scoreboard players add can_buy_n shop 1\n".format(item.name_plain_()))
        nb.close()

    def rnd_shard_drop(self):
        sd = open('../items_py/functions/rnd_shard_drop/drop.mcfunction','w')
        for rank in self.shard:
            for item in self.shard[rank]:
                times = 1
                if "small" in item.name_plain_():
                    times = 2
                for i in range(times):
                    sd.write('execute if score #{0} shop matches 1 run summon marker ~ ~ ~ {{Tags:["{0}","rnd_shard_drop","unspellable"]}}\n'.format(item.name_plain_()))
        sd.write('\nexecute as @e[tag=rnd_shard_drop,limit=1,sort=random] run function items_py:rnd_shard_drop/sort\n')
        sd.write('\nkill @e[tag=rnd_shard_drop]\n')
        sd.write('\ntag @e[type=item,nbt={Item:{tag:{type:"shard"}}},tag=!no_timeout,sort=nearest,limit=1] add no_timeout\n')
        sd.close()

        sd = open('../items_py/functions/rnd_shard_drop/sort.mcfunction','w')
        for rank in self.shard:
            for item in self.shard[rank]:
                sd.write('execute if entity @s[tag={0}] run function items_py:rnd_shard_drop/all/{0}\n'.format(item.name_plain_()))
        sd.close()

    def shards_break(self):
        small = []
        medium = []
        big = []
        for rank in self.shard:
            for item in self.shard[rank]:
                size = item.name_plain_().split("_")[0]
                if size == "small" or size == "spinning":
                    small.append(item.name_plain_())
                elif size == 'medium':
                    medium.append(item.name_plain_())
                else:
                    big.append(item.name_plain_())

        s = open('../items_py/functions/shard_break/break.mcfunction','w')
        for name in small:
            s.write('clear @s amethyst_shard{{name:"{}"}}\n'.format(name))
        s.write("\n")
        for name in medium:
            s.write('execute store result score n_items items_generic run clear @s amethyst_shard{{name:"{0}"}}\n'.format(name))
            s.write('execute unless score n_items items_generic matches 0 run function items_py:shard_break/all/{}\n'.format(name))
        s.write("\n")
        for name in big:
            s.write('execute store result score n_items items_generic run clear @s amethyst_shard{{name:"{0}"}}\n'.format(name))
            s.write('execute unless score n_items items_generic matches 0 run function items_py:shard_break/all/{}\n'.format(name))
        s.write('\nexecute positioned ~ ~1.7 ~ run tag @e[type=item,nbt={Item:{tag:{type:"shard"}}},distance=..0.4] add no_timeout')
        s.close()
