import pygame
import math

import globals
import ball
import flipper
import element

import Collision
import CollisionData

import Player
import Sounds
import HighScores
import ParticleEmitter

# ----------------------------------------------
class Table:

	# ----------------------------------------------
	def __init__(self, size, balls, flippers, elements):
		self.size = size
		if globals.TableAngle > 45:
			self.angle = 45
		elif globals.TableAngle < 20:
			self.angle = 20
		else:
			self.angle = globals.TableAngle									# angle of table

		self.sounds = Sounds.Sounds()
		self.voices = []
#		print(pygame.mixer.get_num_channels())
		
		self.font = pygame.font.Font(globals.String_FontFile, 30)
		pygame.font.init()
		self.highscores = HighScores.HighScores(self.font)

		self.grav_vect = (0, 0.07/ math.cos(math.radians(self.angle)))	# gravity vector
		globals.Gravity = self.grav_vect

		self.balls = balls											# balls list, in case we want multiballs
		self.flippers = flippers									# flippers list
		self.elements = elements									# elements list
		self.elementsplaying = 0
		
		self.tabletop = []
		self.tabletop.append(pygame.image.load(globals.String_TableLayer1))
		self.balls[0].tabletop = self.tabletop
		
		self.launcher = []
		self.launcher.append(pygame.image.load(globals.String_Launcher))
		self.launcherpos = 0
		self.oldlauncherpos = -1
		
		self.special = ParticleEmitter.Special()
		
		self.player = Player.Player(self)
		self.gameover = 0
		self.highscoreentry = 0
		
		self.InitCollisions()
		
		pygame.mixer.music.load(globals.String_Music)
		pygame.mixer.music.play(-1)
		pygame.mixer.music.set_volume(0.4)

	def Init(self):
		self.voices = [pygame.mixer.Channel(0), pygame.mixer.Channel(1)]
		pygame.mixer.stop()

		self.gameover = 0
		self.elementsplaying = 0
		self.highscores.DrawScores()
		
		for flipper in self.flippers:
			flipper.deactivate()
		
		for ball in self.balls:
			ball.Reset()
			
		self.player.Reset()
		self.player.DrawScore()
		#init screen
		self.player.DrawBalls(self.balls[0])
		self.player.Newball(self.balls[0])
		
		self.special.Reset()
		
	def Shutdown(self):
		self.highscores.SaveScores()
		

	# ----------------------------------------------
	def activate_left(self):
		for flipper in self.flippers:
			if flipper.orient == "l":
				if(flipper.is_activated == False): self.sounds.Play(globals.SoundClick1, 0)
				flipper.activate()
				
	# ----------------------------------------------
	def activate_right(self):
		for flipper in self.flippers:
			if flipper.orient == "r":
				if(flipper.is_activated == False): self.sounds.Play(globals.SoundClick1, 0)
				flipper.activate()

	# ----------------------------------------------
	def deactivate_left(self):
		for flipper in self.flippers:
			if flipper.orient == "l":
				flipper.deactivate()

	# ----------------------------------------------
	def deactivate_right(self):
		for flipper in self.flippers:
			if flipper.orient == "r":
				flipper.deactivate()

	# ----------------------------------------------
	def apply_gravity(self, ms):
		temp = ms / globals.forcefactor
		for ball in self.balls:
			ball.velocity = (ball.velocity[0] + self.grav_vect[0] * temp, ball.velocity[1] + self.grav_vect[1] * temp)
			
	# ----------------------------------------------
	def Update(self, ms):
		
		if(self.special.stopped == 0):
			if(self.special.Update(ms)):
				self.sounds.Play(globals.SoundExplode, 0)
			if(self.special.stopped == 1):
				self.player.score += self.special.score
				self.player.DrawScore()
		
		# update the audio
		if(pygame.mixer.music.get_busy() == 0):
			pygame.mixer.music.play(-1)
		
		if(self.special.stopped == 1):
			#apply gravity before collision - but dont set position!!!
			for ball in self.balls:
				self.apply_gravity(ms)
	
			scoreprev = self.player.score
			self.UpdateCollision(ms)
			
			for i in range(1, 9):
				if(self.player.score > i*50000 and scoreprev <= i*50000):
					self.special.Start()
			
			for flipper in self.flippers:
				flipper.Update(ms)
	
			for ball in self.balls:
				ball.Update(ms)

		# if the ball moves below the the table - then it is gone!!
		if(self.balls[0].position[1] > 800 and self.gameover == 0):
			self.sounds.Play(globals.SoundCrowddoh, 0)

			self.balls[0].position = [180, 900]
			pygame.time.wait(1500)
			if(self.player.ballsleft > 0):
				self.player.Newball(self.balls[0])
				self.balls[0].Reset()
			else:
				self.gameover = 1
				self.highscores.AddScore(self.player.score)
				
		self.player.DrawBalls(self.balls[0])
		
		# Update the player
		self.player.Update(ms)

	# ----------------------------------------------
	def draw(self, ms):
#		pygame.draw.rect(globals.screen, globals.white, pygame.Rect(0, 0, self.size[0], self.size[1]), 4)
		self.DrawTableRegions()

		for flipper in self.flippers:
			flipper.draw(ms)
			
		for ball in self.balls:
			ball.draw() 
		
		for element in self.elements:
			element.draw(ms)
		
		if(self.oldlauncherpos != self.launcherpos):
			pos = [365, 586 + self.launcherpos]
			globals.screen.blit(self.launcher[0], pos)
			
		if(self.special.stopped == 0):
			self.special.Draw()

		# self.CollTest.DrawLines()
		# self.CollElementTest.DrawLines()
			
	# ----------------------------------------------
	def CheckLauncher(self):
		ballpos = self.balls[0].position
		if(ballpos[0] > 365 and ballpos[0] < 393 and ballpos[1] > 560 and ballpos[1] < 760):
			return 0
		else:
			return 1
	
	# ----------------------------------------------
	def PullLauncher(self):
		if(self.CheckLauncher() == 1): return
		
		self.oldlauncherpos = self.launcherpos
		pos = [365, 573 + self.launcherpos]
		globals.screen.blit(self.tabletop[0], pos, [pos[0], pos[1], 30, 174])
		self.launcherpos += 3
		if(self.launcherpos > 174): self.launcherpos = 174
		
	# ----------------------------------------------
	def ReleaseLauncher(self):
		if(self.CheckLauncher() == 1): return

		launchvel = self.launcherpos * 0.1
		self.balls[0].velocity = [self.balls[0].velocity[0], self.balls[0].velocity[1] - launchvel]
		self.launcherpos = 0
		self.oldlauncherpos = -1
		self.sounds.Play(globals.SoundBoing, 0)
		
	# ----------------------------------------------
	def DrawTableRegions(self):
		
		for r in globals.UpdateRegions:
			globals.screen.blit(self.tabletop[0], [r[0], r[1]], [r[0], r[1], r[2], r[3]])
		globals.UpdateRegions = []
	
	# ----------------------------------------------
	def InitCollisions(self):
		# collision test objects
		# - Collision collider can be merged into each system. 
		# - One for table, one for each element (if it needs it for activation).
		self.CollTest = Collision.Collider()
		self.CollTest.AddLines(CollisionData.TableTwo[0])
		self.CollTest.AddLines(CollisionData.TableTwo[1])
		self.CollTest.AddLines(CollisionData.TableTwo[2])

		# LEft and Right Chutes
		self.CollTest.AddLines(CollisionData.TableTwo[5])
		self.CollTest.AddLines(CollisionData.TableTwo[6])
		
		# Middle block and top chute entry
		self.CollTest.AddLines(CollisionData.TableTwo[7])
		self.CollTest.AddLines(CollisionData.TableTwo[8])
		self.CollTest.AddLines(CollisionData.TableTwo[9])
		
		# flipper pin
		self.CollTest.AddLines(CollisionData.TableTwo[10])
		self.CollTest.AddLines(CollisionData.TableTwo[11])
		
		# Bumper areas
		self.CollBump = Collision.Collider()
		self.CollBump.AddLines(CollisionData.TableTwo[12])
		
		self.CollObj = Collision.CollObject(self.balls[0].position, self.balls[0].radius)
		
		self.CollElementTest = Collision.Collider()
#		self.CollElementTest.AddLines(CollisionData.TableOne[3])
#		self.CollElementTest.AddLines(CollisionData.TableOne[4])
#		self.CollElementTest.AddLines(CollisionData.TableOne[5])	

	# ----------------------------------------------
	def UpdateCollision(self, ms):
		self.CollObj.pos = self.balls[0].position
		self.CollObj.vec = self.balls[0].velocity
		
		# base table clipping
		self.CollTest.ClipVectorLines(self.CollObj, 0, -1)
		
		# Check a couple of bonus areas
		s1 = [self.balls[0].position[0], self.balls[0].position[1], self.balls[0].radius]
		s2 = [38, 402, 22]
		if (self.CollElementTest.SphereSphereClip(s1, s2) ):
			self.sounds.Play(globals.SoundPolyndr, 0)
			self.player.Score(globals.ScoreSpinner)
		s2 = [22, 104, 20]
		if (self.CollElementTest.SphereSphereClip(s1, s2) ):
			if(self.voices[0] == None): self.voices[0] = self.sounds.Play(globals.VoiceOnScreen, 0)
			elif(self.voices[0].get_busy() == 0): self.voices[0] = self.sounds.Play(globals.VoiceOnScreen, 0)
			self.player.Score(globals.ScoreChute)
		s2 = [341, 353, 20]
		if (self.CollElementTest.SphereSphereClip(s1, s2) ):
			if(self.voices[1] == None): self.voices[1] = self.sounds.Play(globals.VoiceDukka, 0)
			elif(self.voices[1].get_busy() == 0): self.voices[1] = self.sounds.Play(globals.VoiceDukka, 0)
			self.player.Score(globals.ScoreChute)
		
		# test for some simple bump areas
		if (self.CollBump.ClipVectorLines(self.CollObj, 0, -1) > 0):
			self.sounds.Play(globals.SoundDunk, 0)
			self.player.Score(globals.ScoreBumper)
			sz = 10.0 / globals.forcefactor * ms
			if(self.balls[0].position[0] > 180):
				force = [ -sz, -sz ]
			else:
				force = [ sz, -sz ]
			self.CollObj.vec = [self.CollObj.vec[0] + force[0], self.CollObj.vec[1] + force[1]]
				
		# Element collision clipping
		bpos = [self.balls[0].position[0], self.balls[0].position[1], self.balls[0].radius]
		for element in self.elements:
			epos = [element.position[0], element.position[1], element.radius]
			element.Update(ms)
			if(self.CollElementTest.SphereSphereClip(bpos, epos) > 0):
				diff = self.CollElementTest.diff[0] * ms / globals.forcefactor, self.CollElementTest.diff[1] * ms / globals.forcefactor
				self.CollObj.vec = [self.CollObj.vec[0] - diff[0], self.CollObj.vec[1] - diff[1]]
				self.player.Score(globals.ScoreElement)
				self.sounds.Play(globals.SoundJounk, 0)
				
				element.emitter.Start(20, 4.0, 10, 500)
		
		# Check Flipper Collisions
		for flipper in self.flippers:
			flipframe = flipper.frame.count
			if(flipper.coll.ClipVectorLines(self.CollObj, flipframe * 3, 3) > 0):
				if(flipframe > 0): 
					self.CollObj.vec = [self.CollObj.vec[0], self.CollObj.vec[1] * 1.2]
		
		#do some final clipping - should probably move to the ball class
		tempx = self.CollObj.vec[0]
		sz = self.CollObj.r * 4
		if(tempx > sz): tempx = sz
		if(tempx < -sz): tempx = -sz
		tempy = self.CollObj.vec[1]
		if(tempy > sz): tempy = sz
		if(tempy < -sz): tempy = -sz
		self.CollObj.vec = [tempx, tempy]    
		self.balls[0].velocity = self.CollObj.vec