from core.system.client import ClientAssist
from core.ui import boolStr, DialogUi

from siege import game, GrabbedItemLocation, InventoryItem, Locale
from siege.io import DataStream
from siege.network import Message
from siege.util import PixelRect


class ResearchUi(DialogUi):
    def __init__(self, player, tooltip):
        self.player = player
        DialogUi.__init__(self, 'research', PixelRect(300, 200, 240, 300))

        self.categories = {}
        self.materials = ResearchMaterialsUi(player, tooltip)

        #Register UI callbacks
        self.view.register('populate', self.onPopulate)
        self.view.register('clickedItem', self.onClickedItem)
        self.view.register('splitItem', self.onSplitItem)
        self.view.register('clickedMaterials', self.onClickedMaterials)
        self.view.register('researched', self.onResearched)
        self.view.register('showTooltip', tooltip.onShow)
        self.view.onHide.listen(self.hide)
        self.load('html/research.html')

        self.player.entity.reserves.observe('research', self.handleReserveChange)
        ClientAssist.requestReserveCreation('research', 1)

    def show(self, focus=True):
        super(ResearchUi, self).show(focus)
        self.view.execute("App.research.item.reset();")
        ClientAssist.requestReserveCreation('research', 1)

    def hide(self):
        super(ResearchUi, self).hide()
        ClientAssist.requestReserveRestoration('research')
        self.materials.hide()

    def getReserveItem(self):
        reserves = self.player.entity.reserves
        if 'research' not in reserves:
            ClientAssist.requestReserveCreation('research', 1)
            return InventoryItem()
        else:
            return reserves['research'].get(0)

    def onPopulate(self, view, args):
        commands = []
        commands.append("$('#handles .tab-title').text('{}');".format(Locale.getEscaped("ResearchTitle")))
        self.categories = {}
        #Go through all craftables and create a App.Item object for them
        for craftComponent in game.craft.getComponents():
            self.categories[craftComponent.data().category.lower()] = True
        for category in self.categories.keys():
            icon = "../images/category_icon_{}.png".format(category)
            info = "key: '{}', name: '{}', icon: '{}'".format(category, Locale.getEscaped(category), icon)
            commands.append("App.categories.pushObject(App.Category.create({{ {} }}));".format(info))
        view.execute(commands)

    def onClickedItem(self, view, args):
        #Handle when the player clicks on an item
        #Send a request to the server to swap the item in the bag with the grabbed item
        item = self.getReserveItem()
        if item or self.player.grabbed:
            game.audio.play("mods/core/audio/sfx/ui/grab1.ogg")
            packet = DataStream(Message.ITEM_SWAP_WITH_GRAB)
            packet.writeUint8(GrabbedItemLocation.RESERVE)
            packet.writeUint32(self.player.entity.id)
            packet.writeString('research')
            packet.writeUint8(0)
            game.network.getClient().send(packet)

    def onSplitItem(self, view, args):
        item = self.getReserveItem()
        if item and (not self.player.grabbed or item.content == self.player.grabbed.item.content):
            game.audio.play("mods/core/audio/sfx/ui/split.ogg")
            packet = DataStream(Message.ITEM_SPLIT)
            packet.writeUint8(GrabbedItemLocation.RESERVE)
            packet.writeUint32(self.player.entity.id)
            packet.writeString('research')
            packet.writeUint8(0)
            game.network.getClient().send(packet)

    def onClickedMaterials(self, view, args):
        self.materials.toggleVisibility()

    def onResearched(self, view, args):
        category = args[1].toString()
        packet = DataStream(Message.ITEM_RESEARCH)
        packet.writeString(category)
        game.network.getClient().send(packet)

    def handleReserveChange(self, ignored, index, previous, item):
        commands = []
        commands.append("App.research.item.set('quantity', {});".format(item.quantity))
        if item:
            commands.append("App.research.item.set('id', {});".format(item.entity.id))
            commands.append("App.research.item.set('content', {});".format(item.content.id))
            commands.append("App.research.item.set('icon', 'asset://crea/{}');".format(item.entity.render.getIconPath()))
            categories = [] if item.entity.item.isUnique else game.research.getCategories(self.player.entity, item.content.id)
            for category in self.categories.keys():
                commands.append("var category = App.categories.findProperty('key', '{}');".format(category))
                isSelectable = category in categories
                commands.append("category.set('isSelectable', {});".format(boolStr(isSelectable)))
                if not isSelectable:
                    commands.append("category.set('isSelected', false);")
            commands.append("if (App.research.category != null && !App.research.category.get('isSelectable')) { App.research.set('category', null); }")
        else:
            commands.append("App.research.reset();")
        self.view.execute(commands)


class ResearchMaterialsUi(DialogUi):
    def __init__(self, player, tooltip):
        self.player = player
        DialogUi.__init__(self, 'materials', PixelRect(300, 200, 700, 700))
        #Register UI callbacks
        self.view.register('populate', self.onPopulate)
        self.view.register('showTooltip', tooltip.onShow)
        self.player.entity.research.onRecipeChange.listen(self.handleRecipeChange)
        self.load('html/materials.html')

    def onPopulate(self, view, args):
        commands = []
        research = self.player.entity.research
        commands.append("$('#handles .tab-title').text('{}');".format(Locale.getEscaped("ResearchMaterialsTitle")))
        if research.materials:
            commands.append("for (var i = 0; i < {}; ++i) {{".format(len(research.materials)))
            commands[-1] += "App.materialController.addObject(App.MaterialItem.create()); }"
            for index, material in enumerate(research.materials.keys()):
                commands.append("var tempItem = App.materialController.content[{}];".format(index))
                commands.extend(self.updateMaterial(material, len(research.materials[material])))
        view.execute(commands)

    def updateMaterial(self, material, researched):
        commands = []
        commands.append("tempItem.set('content', {});".format(material))
        content = game.content.get(material)
        commands.append("tempItem.set('name', '{}');".format(Locale.getEscaped(content.entity.name)))
        commands.append("tempItem.set('icon', 'asset://crea/{}');".format(content.entity.render.getIconPath()))
        commands.append("tempItem.set('researched', {});".format(researched))
        commands.append("tempItem.set('total', {});".format(len(game.research.materials[material])))
        return commands

    def handleRecipeChange(self, recipe, material):
        commands = []
        materials = self.player.entity.research.materials
        if material not in materials:
            # Material not in research available means it must be a unique material. We don't care about those here.
            return
        researched = len(materials[material])
        if researched == 1:
            commands.append("var tempItem = App.MaterialItem.create();")
            commands.append("App.materialController.addObject(tempItem);")
        else:
            commands.append("var tempItem = App.materialController.findProperty('content', {});".format(material))
        commands.extend(self.updateMaterial(material, researched))
        self.view.execute(commands)
