########################################################################
#	Hello Worlds - Libre 3D RPG game.
#	Copyright (C) 2020  CYBERDEViL
#
#	This file is part of Hello Worlds.
#
#	Hello Worlds is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#
#	Hello Worlds is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
########################################################################


from LUIFrame import LUIFrame
from LUILabel import LUILabel
from LUIProgressbar import LUIProgressbar
from LUILayouts import LUIHorizontalLayout
from LUIVerticalLayout import LUIVerticalLayout
from LUISprite import LUISprite
from LUIObject import LUIObject
from LUIInitialState import LUIInitialState

from core.models import ItemModel

class UI_ItemInfo(LUIFrame):
	def __init__(self, **kwargs):
		LUIFrame.__init__(self, style=LUIFrame.FS_raised, **kwargs)

		self.margin = 0

		self._model = None

		self._descLabelFmt = "Description: {}"
		self._descLabel = LUILabel("", parent=self, margin=0, left=3, top=3)

		self.hide()

	def setModel(self, model):
		self._model = model

		if model:
			self._descLabel.set_text(self._descLabelFmt.format(model.description))

		else: self._modelRemoved()

	def close(self): self.parent = None

	def _modelRemoved(self):
		self._descLabel.set_text(self._descLabelFmt)

class UI_DragItem(LUIObject):
	icons = {
		'unknown'	: "assets/icons/unknown.png",
		'empty'		: "assets/icons/overlay_0.png"
	}
	def __init__(self, *args, **kwargs):
		LUIObject.__init__(self, *args)
		self.width = 48
		self.height = 48
		self._icon = LUISprite(self, self.icons['empty'], width=self.width, height=self.height)

		self.set_pos(100,100)

class UI_Item(LUIObject):
	icons = {
		'unknown'	: "assets/icons/unknown.png",
		'empty'		: "assets/icons/overlay_0.png"
	}
	def __init__(self, *args, **kwargs):
		# Without solid=True it doesn't receive mouse-events
		LUIObject.__init__(self, *args, solid=True)

		self.width = 48
		self.height = 48

		self._model = None
		self._isDragging = False
		self._backupParent = self.parent
		self._dragItem = None

		self._icon = LUISprite(self, self.icons['empty'], width=self.width, height=self.height)
		self._label = LUILabel("", parent=self, margin=0, left=0, bottom=0)

		self._overlay = None

		LUIInitialState.init(self, kwargs)

	def mousePos(self):
		if base.mouseWatcherNode.hasMouse():
			mpos = base.mouseWatcherNode.getMouse()
			mousePos = (mpos.getX() * base.getAspectRatio(), mpos.getY())

			screenWidth = base.win.getProperties().getXSize()
			screenHeight = base.win.getProperties().getYSize()
			ratio = base.getAspectRatio()

			# https://stackoverflow.com/questions/929103/convert-a-number-range-to-another-range-maintaining-ratio
			left = (((mousePos[0] - -ratio) * (screenWidth - 0)) / (ratio - -ratio)) + 0
			top = (((mousePos[1] - 1) * (screenHeight - 0)) / (-1 - 1)) + 0

			return (left, top)
		return(0,0)

	def _dragWatcher(self, event=None):
		if not self._dragItem:
			print("Start drag")
			self._dragItem = UI_DragItem(base.luiRegion.root)
			self.unbind('mousemove')
			taskMgr.add(self._dragTask, 'dragWatcher')

	def _dragTask(self, task):
		self._dragItem.set_pos(self.mousePos())
		return task.cont

	def _stopDrag(self):
		if self._dragItem:
			print("Stop drag")
			taskMgr.remove('dragWatcher')
			self._dragItem.parent = None
			self._dragItem = None

	def on_mouseover(self, event):
		if self._model:
			pos = self.get_abs_pos()
			pos -= (-50,50)
			base.uiManager.spellInfoFrame.setModel(self._model)
			base.uiManager.spellInfoFrame.set_pos(pos)
			base.uiManager.spellInfoFrame.show()

	def on_mouseout(self, event):
		if self._model:
			base.uiManager.spellInfoFrame.hide()

	def on_mousedown(self, event):
		if self._model:
			#self.bind('mousemove', self._dragWatcher) # uncomment to enable drag 'n drop (that isn't complete yet)
			self._addOverlay()

	def on_mouseup(self, event):
		if self._model:
			self._stopDrag()
			self._removeOverlay()

	def _addOverlay(self):
		overlayPath = "assets/icons/overlay_1.png"
		if not self._overlay:
			self._overlay = LUISprite(self, overlayPath, width=self.width, height=self.height)

	def _removeOverlay(self):
		if self._overlay:
			self._overlay.parent = None
			self._overlay = None

	def setModel(self, model):
		self._model = model

		if model:
			self._icon.set_texture(model.iconPath, resize=False)
			self._label.set_text(model.name)

		else: self._modelRemoved()

	def _modelRemoved(self):
		self._icon.set_texture(self.icons['empty'], resize=False)
		self._label.set_text("")

class UI_SpellBar(LUIFrame):
	def __init__(self, **kwargs):
		LUIFrame.__init__(self, style=LUIFrame.FS_sunken, **kwargs)

		self.height = 68
		self.margin = 0

		screenHeight = base.win.getProperties().getYSize()

		self.top = screenHeight - 68 - 3
		self.center_horizontal = True

		self._layout = LUIHorizontalLayout(parent=self)
		self._layout.spacing = 3

		maxItems = 10
		self._items = []
		for i in range(0, maxItems):
			self._items.append(UI_Item(self._layout.cell()))

		""" TODO TMP add some spells for testing
		These spells or actions? shouldn't be static like this..
		"""
		spell1Test = ItemModel(
			name="Melee 1",
			iconPath="assets/icons/attack_0.png",
			desc="Melee attack level 1")
		self._items[0].setModel(spell1Test)

		spell1Test = ItemModel(
			name="Melee 2",
			iconPath="assets/icons/attack_0.png",
			desc="Melee attack level 2")
		self._items[1].setModel(spell1Test)

		base.accept('WINDOW_RESIZED', self.reposition)

	def reposition(self):
		self.top = base.win.getProperties().getYSize() - self.height - 10

	def close(self): self.parent = None

class UI_PlayerInfoBox(LUIFrame):
	def __init__(self, parent=None, top=10, left=10):
		if not parent: parent = base.luiRegion.root
		LUIFrame.__init__(self, parent=parent, style=LUIFrame.FS_sunken, width=170, height=80, margin=0, top=top, left=left)

		self._layout = LUIVerticalLayout(self)

		self.nameLabel = LUILabel(parent=self._layout.cell(), text="Name: ")
		self.healthBar = LUIProgressbar(parent=self._layout.cell(), width=145, label_fmt="Health: {value}/{max}")
		self.energyBar = LUIProgressbar(parent=self._layout.cell(), width=145, label_fmt="Energy: {value}/{max}")


		self.healthBar.set_max(base.world.player.character.stats.health.max)
		self.healthBar.set_value(base.world.player.character.stats.health.value)

		self.energyBar.set_max(base.world.player.character.stats.energy.max)
		self.energyBar.set_value(base.world.player.character.stats.energy.value)

		base.world.player.character.stats.health.valueChanged.connect(self._healthChanged)
		base.world.player.character.stats.energy.valueChanged.connect(self._energyChanged)

	def _healthChanged(self, value): self.healthBar.set_value(value)
	def _energyChanged(self, value): self.energyBar.set_value(value)

	def close(self): self.parent = None

class UI_CreatureInfoBox:
	def __init__(self, parent=None, top=100, left=10):
		if not parent: parent = base.luiRegion.root

		self._currentSpawnId = -1

		self._container = LUIFrame(parent=parent, width=175, height=55, style=LUIFrame.FS_sunken, margin=0, top=top, left=left)

		self.nameLabel = LUILabel(parent=self._container, text="Name: ", top=0)
		self.healthBar = LUIProgressbar(parent=self._container, width=145, top=20, label_fmt="Health: {value}/{max}")

		base.world.npcsManager.selectedNpcModel.changed.connect(self._selectionChanged)

		self.hide()

	def hasMouse(self): return self._container.hasMouse()

	def _selectionChanged(self, spawnId):
		if self._currentSpawnId == spawnId and self._currentSpawnId != -1:
			# Clicked twice or more
			# This is a TMP-test.. remove later TODO
			npc = base.world.npcsManager.getSpawn(self._currentSpawnId) # creaturesManager.Creature
			npc.stats.health.value -= 10
			if npc.stats.health.value <= 0: # NPC died
				spawnId = -1

		# Disconnect previously set connections
		if self._currentSpawnId != -1 and self._currentSpawnId != spawnId:
			oldNpc = base.world.npcsManager.getSpawn(self._currentSpawnId) # creaturesManager.Creature
			oldNpc.stats.health.valueChanged.disconnect(self._healthChanged)
			oldNpc.removeSelectPlane()

		# Hide if selected id is -1
		if spawnId == -1:
			self.hide()
			self._currentSpawnId = -1
			return

		if self._currentSpawnId != spawnId:

			self.show()

			npc = base.world.npcsManager.getSpawn(spawnId) # creaturesManager.Creature
			npc.addSelectPlane()

			# Name
			self.nameLabel.text = "{0} (id: {1} lvl: {2})".format(npc.data.name, npc.id, npc.stats.level.value)

			# Health
			self.healthBar.set_max(npc.stats.health.max)
			self.healthBar.set_value(npc.stats.health.value)

			self._currentSpawnId = spawnId

			npc.stats.health.valueChanged.connect(self._healthChanged)

	def _healthChanged(self, value):
		npc = base.world.npcsManager.getSpawn(self._currentSpawnId)
		self.healthBar.set_value(npc.stats.health.value)

	def close(self):
		self._container.parent = None
		self._container = None

	def hide(self):
		self._container.hide()

	def show(self):
		self._container.show()

	def isVisible(self): return self._container.visible
