# -*- coding: utf-8 -*-

from json import *
from inspect import getmembers

class NbtError(Exception):
    pass
class LoreError(NbtError):
    pass
class StatError(NbtError):
    pass
class StatsError(NbtError):
    pass

class Lore:

    def __init__(self, l = None):
        if isinstance(l, list):
            for i,line in enumerate(l):
                if not isinstance(line, JPar):
                    raise LoreError("Must be a JPar in [{0}]".format(i))
        self.lore = l

    def newline(self, l):
        if isinstance(l, JPar):
            self.lore.append(l)
        elif isinstance(l, (JTxt, JLine, str)):
            self.lore.append(JPar([l]))
        else:
            print('Must be a Json type or str')

    def blankline(self):
        self.lore.append(JPar(''))

    def get(self):
        txt = []
        for par in self.lore:
            txt.append("{0}".format(par.get()))
        return "["+','.join(txt)+"]"

    def get_book(self):
        txt = ['\n\t\t\t\t\t\t{"text":"","bold":false,"italic":false,"underlined":false,"obfuscated":false}']
        for i, par in enumerate(self.lore):
            if i < len(self.lore)-1:
                txt.append("\n\t\t\t\t\t\t{0},{1}".format(par.get_book(),"{"+'"text":"\\n"'+"}"))
            else:
                txt.append("\n\t\t\t\t\t\t{0}".format(par.get_book()))
        return "["+','.join(txt)+"\n\t\t\t\t]"

class Stat:

    uuid = 1

    sl = ['any','hand','mainhand','offhand','armor']
    mc = ['dmg', 'hp', 'speed', 'knock_resist', 'armor', 'armor_thoughness', 'attack_speed']
    custom = ['curse', 'luck', 'mana_speed', 'mana_cost', 'mana_capacity', 'kills_capacity']
    tl = mc + custom

    def __init__(self, type, value, slot = 'any'):
        if type not in Stat.tl:
            raise StatError('type must be one of {}'.fomrat(Stat.tl))
        if not isinstance(value, (int, float)):
            raise StatError('value must be one of int or float')
        if slot not in Stat.sl:
            raise StatError('slot must be one of {}'.fomrat(Stat.sl))

        self.type = type
        self.value = value
        self.slot = slot
        self.uuid = Stat.uuid

        Stat.uuid += 1

    def attibute(self, armor_piece = None):
        mc = {'dmg': 'attack_damage', 'hp':'max_health', 'speed':'movement_speed', 'knock_resist':'knockback_resistance', 'armor':'armor', 'armor_thoughness':'armor_toughness', 'attack_speed':'attack_speed'}
        if self.type in mc and self.slot != 'any':
            slot = self.slot if self.slot != 'armor' else armor_piece
            if self.slot == 'hand':
                return '{{AttributeName:"generic.{0}",Name:"generic.{0}",Amount:{1},Operation:0,UUID:[I;{2},{2},{2},{2}],Slot:"mainhand"}},{{AttributeName:"generic.{0}",Name:"generic.{0}",Amount:{1},Operation:0,UUID:[I;{2},{2},{2},{2}],Slot:"offhand"}}'.format(mc[self.type], self.value, self.uuid)
            else:
                return '{{AttributeName:"generic.{0}",Name:"generic.{0}",Amount:{1},Operation:0,UUID:[I;{2},{2},{2},{2}],Slot:"{3}"}}'.format(mc[self.type], self.value, self.uuid, slot)
        return ''

class Stats:

    def __init__(self, stats = []):

        self.stats = {}
        self.add(stats)

    def add(self, l = []):
        # Check is list or Stat
        if isinstance(l, Stat):
            l = [l]
        elif isinstance(l, list):
            for i,stat in enumerate(l):
                if not isinstance(stat, Stat):
                    raise StatsError('stat[{}] must be a Stat obj'.format(i))
        else:
            raise Statserror('l must be stat a list of Stats')

        for stat in l:
            # Type not registred
            if stat.type not in self.stats:
                self.stats[stat.type] = [stat]
            # Type registred
            else:
                # Slot conflict check
                for s in self.stats[stat.type]:
                    if stat.slot == s.slot:
                        raise StatsError("{}: {} {} conflicted with {}: {} {}. Can't have two of the same slot.".format( stat.type, stat.value, stat.slot, s.type, s.value, s.slot ) )
                # Conflict passed
                self.stats[stat.type].append(stat)

    def nbt(self):
        txt = []
        for type in self.stats:
            tmp = []
            for stat in self.stats[type]:
                if stat.slot == 'hand':
                    tmp.append('{{value:{},slot:{}}}'.format(stat.value, 'mainhand'))
                    tmp.append('{{value:{},slot:{}}}'.format(stat.value, 'offhand'))
                else:
                    tmp.append('{{value:{},slot:{}}}'.format(stat.value, stat.slot))
            txt.append("{}:[{}]".format(type, ','.join(tmp)))

        return "stats:{"+','.join(txt)+'}'

    def lore(self):
        txt = []
        dic = {
                "hp":"\\\\uf810",
                "dmg":"\\\\uf811",
                "attack_speed":"\\\\uf812",
                "speed":"\\\\uf813",
                "armor":"\\\\uf814",
                "armor_thoughness":"\\\\uf815",
                "knock_resist":"\\\\uf816",
                "mana_capacity":"\\\\uf817",
                "mana_speed":"\\\\uf818",
                "mana_cost":"\\\\uf819",
                "kills_capacity":"\\\\uf81a",
                "luck":"\\\\uf81b",
                "curse":"\\\\uf81c"
            }

        for type in self.stats:
            for stat in self.stats[type]:
                l = [ JTxt("  \\\\u2022 {:+}".format(stat.value), italic = True ) ]
                if type in ['luck', 'mana_cost']:
                    l.append( JTxt('%', italic = True ))
                l.append( JTxt(" "+dic[stat.type], 'white', italic = True ) )
                if stat.slot != 'any':
                    if stat.slot == 'armor':
                        l.append( JTxt(' (equipped)', italic = True ) )
                    else:
                        l.append( JTxt(' ({})'.format(stat.slot), italic = True ) )
                txt.append( JPar([ JLine( l ) ]) )

        if len(txt) > 0:
            txt.insert(0, JPar(['Stats: '], 'gray'))
        return txt

    def attibutes(self, armor_piece = None):
        txt = []
        for type in self.stats:
            for stat in self.stats[type]:
                tmp = stat.attibute(armor_piece)
                if tmp != '':
                    txt.append(tmp)
        if len(txt) > 0:
            return ',AttributeModifiers:['+','.join(txt)+']'
        return ''

class Enchantment:

    def __init__(self):
        pass
