########################################################################
#	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/>.
#
########################################################################


# Panda Bullet
from panda3d.bullet import BulletWorld, BulletDebugNode

# Local
from core.mapLoader import MapLoader
from core.character import PlayerCharacterModel
from core.player import PlayerCharacter, PlayerController
from core.npcsManager import NPCsManager

from core.db import GenericSpawnData, PlayerData


class World:
	def __init__(self, rootNode=None):
		if not rootNode: rootNode = base.render
		# Setup Bullet
		self._world = BulletWorld()
		self._worldNP = rootNode.attachNewNode('World')

		self._playerCharacter = None
		self._playerController = None

		""" Setup test character (which is played by a Player)
		So this is TODO for future character creation.
		"""
		"""
		0	characterId (npc or player-character)
		1	x
		2	y
		3	z
		4	o
		"""
		spawnData = GenericSpawnData(0, [2,0,0,48,0])

		"""
		0	name
		1	dirName
		2	file
		3	animations {}
		4	stats {}
		5	collisionShape {}
		6	speciesId
		7	fractionId
		8	spellIds []
		"""
		characterData = PlayerData(_id=1, data = ['Debug', 'character_2', 'female.egg', {}, {}, {}, 1, 2, [1,2,3,4]])
		self.character = PlayerCharacterModel(characterData, spawnData)

		# Debuging
		self.debugNP = self._worldNP.attachNewNode(BulletDebugNode('Debug'))
		self.debugNP.show()
		self.debugNP.node().showNormals(True)
		self._world.setDebugNode(self.debugNP.node())

		# Map loader
		self._mapLoader = MapLoader(self._world, self._worldNP)

		# NPC's
		self._npcsManager = NPCsManager(self._world, self._worldNP)

		# Game objects
		# ..

		base.accept('x', self.toggleDebug)
		taskMgr.add(self.update, 'updateWorld')

		self.debugNP.hide()

	@property
	def npcsManager(self): return self._npcsManager

	@property
	def mapLoader(self): return self._mapLoader

	@property
	def player(self): return self._playerCharacter

	@property
	def playerController(self): return self._playerController

	@property
	def world(self): return self._world

	def destroy(self):
		taskMgr.remove('updateWorld')
		base.uiManager.destroyGameUI()
		if self.player:
			self.player.destroy()
			self._playerCharacter = None
		self.npcsManager.clear()
		self.mapLoader.unload()

	def loadMap(self, mapId):
		self.mapLoader.load(mapId, self._onMapLoaded)

	def _onMapLoaded(self):
		self._playerController = PlayerController(mapId=self.mapLoader.currentId)

		base.uiManager.loadGameUI()

		self._playerCharacter = PlayerCharacter(self._world, self._worldNP, self.character)
		self._playerController.character = self._playerCharacter

		self.npcsManager.setPlayer(self.player)
		self.npcsManager.setSpawnData(
			self.mapLoader.currentMap.spawns
		)

		base.uiManager.characterChanged()

	def toggleDebug(self):
		if self.debugNP.isHidden(): self.debugNP.show()
		else: self.debugNP.hide()

	def doPhysics(self, dt): self._world.doPhysics(dt, 10, 0.008)

	def update(self, task):
		dt = globalClock.getDt()
		self.doPhysics(dt)
		return task.cont
