# -*- coding: utf-8 -*-
"""
UTc! module: src.tankchan

Purpose
=======
 Provides routines for creating, maintaining, and rendering Tank-chans.
 
Legal
=====
 All code, unless otherwise indicated, is original, and subject to the
 terms of the GPLv3, which is provided in COPYING.
 
 (C) Neil Tallim, 2009
"""
import random
import pygame
import OpenGL.GL as GL

import gameobjects
import path_utils

import rendering.rendering as rendering

_EXPLOSION_HULL_TEXTURES = [] #: A list of all textures that may be used to show hull impacts.
_EXPLOSION_HULL_GROWTH_TIME = 0.25 #: The time required for hull explosions to reach peak size.
_EXPLOSION_HULL_DECAY_TIME = 0.75 #: The time required for hull explosions to disappear.
_EXPLOSION_HULL_PEAK_SIZE = 1.0 #: The peak size of hull explosions.

_EXPLOSION_MISSILE_TEXTURES = [] #: A list of all textures that may be used to show missile explosions.
_EXPLOSION_MISSILE_GROWTH_TIME = 0.5 #: The time required for missile explosions to reach peak size.
_EXPLOSION_MISSILE_DECAY_TIME = 2.0 #: The time required for missile explosions to disappear.
_EXPLOSION_MISSILE_PEAK_SIZE = 3.0 #: The peak size of missile explosions.

_EXPLOSION_SHIELD_TEXTURES = [] #: A list of all textures that may be used to show shield impacts.
_EXPLOSION_SHIELD_GROWTH_TIME = 0.25 #: The time required for shield explosions to reach peak size.
_EXPLOSION_SHIELD_DECAY_TIME = 0.75 #: The time required for shield explosions to disappear.
_EXPLOSION_SHIELD_PEAK_SIZE = 1.0 #: The peak size of shield explosions.

_EXPLOSION_SHIP_TEXTURES = [] #: A list of all textures that may be used to show ship explosions.
_EXPLOSION_SHIP_GROWTH_TIME = 0.5 #: The time required for ship explosions to reach peak size.
_EXPLOSION_SHIP_DECAY_TIME = 4.5 #: The time required for ship explosions to disappear.
_EXPLOSION_SHIP_PEAK_SIZE = 10.0 #: The peak size of ship explosions.

class _Effect(gameobjects.GameObject):
	"""
	An abstract representation of explosions that may appear within game-space.
	"""
	_alive = True #: False when this effect has run its course.
	_opacity = 1.0 #: The current opacity of this effect.
	_size = 0.0 #: The current size of this effect.
	_size_peak = None #: The size of this effect at its peak.
	_texture = None #: The OpenGL texture ID of the texture to display.
	_time_decay = None #: The amount of time it takes to disappear.
	_time_decay_remaining = None #: The amount of time left before this effect is gone.
	_time_growth = None #: The amount of time it takes to reach peak size.
	_time_growth_remaining = None #: The amount of time left before peak size is reached.
	
	def __init__(self, position):
		"""
		Initialises the position of this effect.
		
		@type position: sequence(3)
		@param position: The (x, y, z) co-ordinates of this effect in game-space.
		"""
		gameobjects.GameObject.__init__(self)
		self.setPosition(position)
		
	def isAlive(self):
		"""
		Indicates whether this effect is still active.
		
		@rtype: bool
		@return: True if this effect is still active.
		"""
		return self._alive
		
	def render(self):
		"""
		Displays this effect within visual-space, if it has any reason to appear.
		"""
		if not self._alive or not self._render:
			return
			
		GL.glColor(1.0, 1.0, 1.0, self._opacity)
		rendering.renderOrtho(self._pos_x, self._pos_y, self._pos_z, self._size, self._texture)
		
	def tick(self, seconds):
		"""
		Updates the size and opacity of this effect, and marks it as dead once it
		has run its course.
		
		@type seconds: float
		@param seconds: The amount of time that passed since the last update.
		
		@rtype: bool
		@return: False if this effect has run its course.
		"""
		if not self._alive:
			return False
			
		if self._time_growth_remaining: #Still growing.
			self._time_growth_remaining -= seconds
			self._size = self._size_peak * (1.0 - max(0.0, self._time_growth_remaining / self._time_growth))
			if self._time_growth_remaining <= 0.0:
				self._time_decay_remaining += self._time_growth_remaining
				self._time_growth_remaining = None
				self._size = self._size_peak
		else: #In decline.
			self._time_decay_remaining -= seconds
			self._opacity = max(0.0, self._time_decay_remaining / self._time_decay)
			if self._time_decay_remaining <= 0.0:
				self._alive = False
				return False
		return True
		
class HullExplosion(_Effect):
	"""
	A representation of hull-impact effects.
	"""
	def __init__(self, position):
		"""
		Initialises the parameters of this effect, determining what it looks like
		and how it will develop.
		
		@type position: sequence(3)
		@param position: The (x, y, z) co-ordinates of this effect in game-space.
		"""
		_Effect.__init__(self, position)
		self._time_growth_remaining = self._time_growth = _EXPLOSION_HULL_GROWTH_TIME
		self._time_decay_remaining = self._time_decay = _EXPLOSION_HULL_DECAY_TIME
		self._size_peak = _EXPLOSION_HULL_PEAK_SIZE
		self._texture = random.choice(_EXPLOSION_HULL_TEXTURES)
		
class MissileExplosion(_Effect):
	"""
	A representation of missile-explosion effects.
	"""
	def __init__(self, position):
		"""
		Initialises the parameters of this effect, determining what it looks like
		and how it will develop.
		
		@type position: sequence(3)
		@param position: The (x, y, z) co-ordinates of this effect in game-space.
		"""
		_Effect.__init__(self, position)
		self._time_growth_remaining = self._time_growth = _EXPLOSION_MISSILE_GROWTH_TIME
		self._time_decay_remaining = self._time_decay = _EXPLOSION_MISSILE_DECAY_TIME
		self._size_peak = _EXPLOSION_MISSILE_PEAK_SIZE
		self._texture = random.choice(_EXPLOSION_MISSILE_TEXTURES)
		
class ShieldExplosion(_Effect):
	"""
	A representation of shield-impact effects.
	"""
	def __init__(self, position):
		"""
		Initialises the parameters of this effect, determining what it looks like
		and how it will develop.
		
		@type position: sequence(3)
		@param position: The (x, y, z) co-ordinates of this effect in game-space.
		"""
		_Effect.__init__(self, position)
		self._time_growth_remaining = self._time_growth = _EXPLOSION_SHIELD_GROWTH_TIME
		self._time_decay_remaining = self._time_decay = _EXPLOSION_SHIELD_DECAY_TIME
		self._size_peak = _EXPLOSION_SHIELD_PEAK_SIZE
		self._texture = random.choice(_EXPLOSION_SHIELD_TEXTURES)
		
class ShipExplosion(_Effect):
	"""
	A representation of ship-explosion effects.
	"""
	def __init__(self, position):
		"""
		Initialises the parameters of this effect, determining what it looks like
		and how it will develop.
		
		@type position: sequence(3)
		@param position: The (x, y, z) co-ordinates of this effect in game-space.
		"""
		_Effect.__init__(self, position)
		self._time_growth_remaining = self._time_growth = _EXPLOSION_SHIP_GROWTH_TIME
		self._time_decay_remaining = self._time_decay = _EXPLOSION_SHIP_DECAY_TIME
		self._size_peak = _EXPLOSION_SHIP_PEAK_SIZE
		self._texture = random.choice(_EXPLOSION_SHIP_TEXTURES)
		
def init():
	"""
	Loads all textures needed by this module, speeding up the process of
	displaying them on-demand in-game.
	
	This function must be invoked before any classes from this module may be
	instantiated.
	"""
	texture_path = path_utils.getTexturesPath()
	
	_EXPLOSION_HULL_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-hull-1.png")))
	_EXPLOSION_HULL_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-hull-2.png")))
	_EXPLOSION_HULL_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-hull-3.png")))
	
	_EXPLOSION_MISSILE_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-missile-1.png")))
	_EXPLOSION_MISSILE_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-missile-2.png")))
	_EXPLOSION_MISSILE_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-missile-3.png")))
	
	_EXPLOSION_SHIELD_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-shield-1.png")))
	_EXPLOSION_SHIELD_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-shield-2.png")))
	_EXPLOSION_SHIELD_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-shield-3.png")))
	
	_EXPLOSION_SHIP_TEXTURES.append(rendering.buildTexture(pygame.image.load(texture_path + "explosion-ship-1.png")))
	explosion = rendering.buildTexture(pygame.image.load(texture_path + "explosion-ship-2.png"))
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	explosion = rendering.buildTexture(pygame.image.load(texture_path + "explosion-ship-3.png"))
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	explosion = rendering.buildTexture(pygame.image.load(texture_path + "explosion-ship-4.png"))
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	explosion = rendering.buildTexture(pygame.image.load(texture_path + "explosion-ship-5.png"))
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	_EXPLOSION_SHIP_TEXTURES.append(explosion)
	