from functools import partial

from core.ui import boolStr, DialogUi

from siege import game, GrabbedItemLocation, Locale, SkillType
from siege.io import DataStream
from siege.log import Log
from siege.network import Message
from siege.util import PixelRect


class TalentUi(DialogUi):
    def __init__(self, player, tooltip):
        self.player = player
        windowSize = game.render.getWindowSize()
        width = 400
        height = 600
        x = 25
        y = (windowSize.y / 2) - (height / 2)
        DialogUi.__init__(self, 'talent', PixelRect(x, y, width, height))
        #Register UI callbacks
        self.view.register('populate', self.onPopulate)
        self.view.register('purchase', self.onPurchase)
        self.view.register('clickedSkill', self.onClickedSkill)
        self.view.register('showTooltip', tooltip.onShow)
        self.load('html/talent.html')

        #Talent Listeners
        talents = self.player.entity.talents
        for talent in talents.ordered:
            talent.level.onChange.listen(partial(self.onLevelChanged, talent))
            talent.points.onChange.listen(partial(self.onPointsChanged, talent))
            talent.stored.onChange.listen(partial(self.onStoredChanged, talent))
            talent.onSkillChanged.listen(self.onSkillChanged)

    def onPopulate(self, view, args):
        commands = []
        for talent in self.player.entity.talents.ordered:
            commands.append("var talent = App.Talent.create({{id: '{}'}});".format(talent.name))
            commands.append("talent.name = '{}';".format(Locale.getEscaped(talent.name)))
            commands.append("talent.icon = 'asset://crea/{}';".format(talent.icon))
            commands.append("talent.tracker.set('level', {});".format(talent.level.get()))
            commands.append("talent.tracker.points.set('value', {});".format(talent.points.get()))
            commands.append("talent.tracker.points.set('max', {});".format(talent.getPointsToLevel()))
            commands.append("talent.stored = {};".format(talent.stored.get()))
            for skill in talent.getSkills():
                commands.append("var skill = App.Skill.create();")
                commands.append("skill.id = '{}';".format(skill.name))
                commands.append("skill.name = '{}';".format(Locale.getEscaped(skill.name)))
                commands.append("skill.icon = 'asset://crea/{}';".format(skill.icon))
                commands.append("skill.level = {};".format(skill.level))
                commands.append("skill.unlockLevel = {};".format(skill.unlockLevel))
                isAvailable = talent.level.get() >= skill.unlockLevel
                commands.append("skill.isAvailable = {};".format(boolStr(isAvailable)))
                commands.append("skill.cost = '{}';".format(skill.getCost()))
                commands.append("talent.skills.pushObject(skill);")
            commands.append("App.talents.pushObject(talent);")
        commands.append("App.talents.content[0].set('isSelected', true);")
        commands.append("App.talentView.set('selected', App.talents.content[0]);")
        self.view.execute(commands)

    def onPurchase(self, view, args):
        talentId = args[1].toString()
        skillId = args[2].toString()
        talent = self.player.entity.talents.get(talentId)
        skill = talent.get(skillId)
        if talent.stored.get() < skill.getCost():
            Log.info("Not enough stored TP({}) to purchase skill {} for {}TP".format(talent.stored.get(), skillId, skill.getCost()))
            return

        #Send a request to the server to purchase skill
        request = DataStream(Message.TALENT_PURCHASE_SKILL)
        request.writeString(talentId)
        request.writeString(skillId)
        game.network.getClient().send(request)

    def onLevelChanged(self, talent, previous, current):
        commands = []
        commands.append("var talent = App.talents.findProperty('id', '{}');".format(talent.name))
        commands.append("talent.tracker.set('level', {});".format(current))
        commands.append("talent.tracker.points.set('max', {});".format(talent.getPointsToLevel()))
        for index, skill in enumerate(talent.getSkills()):
            if current == skill.unlockLevel:
                commands.append("talent.skills.content[{}].set('isAvailable', true);".format(index))
        self.view.execute(commands)

    def onPointsChanged(self, talent, previous, current):
        commands = []
        commands.append("var talent = App.talents.findProperty('id', '{}');".format(talent.name))
        commands.append("talent.tracker.points.set('value', {});".format(current))
        self.view.execute(commands)

    def onStoredChanged(self, talent, previous, current):
        commands = []
        commands.append("var talent = App.talents.findProperty('id', '{}');".format(talent.name))
        commands.append("talent.set('stored', {});".format(current))
        self.view.execute(commands)

    def onSkillChanged(self, talent, skill, previousLevel, currentLevel):
        commands = []
        commands.append("var talent = App.talents.findProperty('id', '{}');".format(talent.name))
        commands.append("var skill = talent.skills.findProperty('id', '{}');".format(skill.name))
        commands.append("skill.set('level', {});".format(skill.level))
        commands.append("skill.set('cost', {});".format(skill.getCost()))
        self.view.execute(commands)

    def onClickedSkill(self, view, args):
        talentId = args[1].toString()
        skillId = args[2].toString()
        talent = self.player.entity.talents.get(talentId)
        skill = talent.get(skillId)
        #Only allow active skills to be grabbed
        if skill.type is SkillType.Active and skill.level > 0:
            if self.player.grabbed:
                game.network.getClient().send(DataStream(Message.ITEM_RETURN_GRAB))
            request = DataStream(Message.ITEM_SWAP_WITH_GRAB)
            request.writeUint8(GrabbedItemLocation.SKILL)
            request.writeString(talentId)
            request.writeString(skillId)
            game.network.getClient().send(request)
