###############################################################################
# File:        pgTools.py
# Appointment: PyGame tools
# Project:     pg
# Author:      AR
# History:
# 15.11.2012 CColourVolMaker was added
# 25.10.2012 added DashedLine
# 25.09.2012 Created
###############################################################################
import math
import os
import pygame
import zx


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Returns 'blured' image taken from image
# Delay - zx.CDelay object
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def BlurImage(image, aDelay = None, aLogFunc = None):
    if image is None:
        return None
        
    img_w = image.get_width()
    img_h = image.get_height()
    blur_img = pygame.Surface((int(img_w), int(img_h)))
    kernel_size = 4.0
    kernel_half = kernel_size / 2.0
   
    for y in range(0, int(img_h)):
        if aLogFunc is not None and y > 0 and y % 10 == 0:
            aLogFunc('...BlurImage: processed ' + str(y) + ' from ' + str(img_h) + ' lines')
        for x in range(0, int(img_w)):
            r, g, b, temp_r, temp_g, temp_b, temp_a, count = 0, 0, 0, 0, 0, 0, 0, 0
            for kernel_offset_y in range(0 - int(kernel_half), 0 + int(kernel_half)):
               if zx.Suspend(aDelay):
                   return None # cancelled
               for kernel_offset_x in range(0 - int(kernel_half), 0 + int(kernel_half)):
                   # Don't check outside screen edges...
                   if (x + kernel_offset_x > 0
                       and x + kernel_offset_x < img_w
                       and y + kernel_offset_y > 0
                       and y + kernel_offset_y < img_h):
                      temp_r, temp_g, temp_b, temp_a = image.get_at((x + kernel_offset_x, y + kernel_offset_y))
            
                   r += temp_r
                   g += temp_g
                   b += temp_b
                   count += 1
         
            if (r > 0):
               r = r / count
            if (g > 0):
               g = g / count
            if (b > 0):
               b = b / count
       
            col = pygame.Color(r, g, b, 0)
            blur_img.set_at((x,y), col)

    return blur_img
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Returns a font from file. Creates a system font if file does not exist or bad
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def LoadFont(aFileName, aSize):
    try:
        # Try to load font
        return pygame.font.Font(aFileName, aSize)
    except:
        # Not found - return system font
        return pygame.font.Font(None, aSize)
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        
        
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Draws a dashed line between 2 points
# If color* is None - it's not painted at all (for cases when this colour is the same as background)
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def DashedLine(surface, color1, color2, pos1, pos2, increment):
    YDiff = float(pos2[1]-pos1[1])
    XDiff = float(pos2[0]-pos1[0])
    Length = math.sqrt((XDiff**2)+(YDiff**2))
    colornumber = 0
    Color = color1
    for pos in xrange(int(round(Length))):
        if Color is not None:
            Position = (int(round(((pos/Length)*XDiff)+pos1[0])), int(round(((pos/Length)*YDiff)+pos1[1])))
            surface.set_at(Position,Color)
        colornumber += 1
        if colornumber == increment:
            colornumber = 0
            if Color == color1:
                Color = color2
            else:
                Color = color1
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Drawing a text on a surface aScreen in coordinates aX, aY
# if aXCenter id true, aX is concidered in the centre
# Returns a text rect
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def DrawText(aScreen, aText, aX, aY, aFont, aColour, aXCenter = False, aYCenter = False):
    renderText = aFont.render(aText, True, aColour)
    textRect = renderText.get_rect()
    if aXCenter:
        textRect.centerx = aX
    else:
        textRect.left = aX
    if aYCenter:
        textRect.centery = aY
    else:
        textRect.top = aY
    aScreen.blit(renderText, textRect)
    return textRect
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


#===============================================================================
# This class is usefull to create a 'volume' effect
#===============================================================================
class CColourVolMaker:
    #---------------------------------------------------------------------------
    # aColour - a colour tuple (r,g,b)
    # aSteps - number of steps
    # aStarK - 'start koefficient', must be 0..1; 0 means start from 'black', 1 - has no sence, because the max colour is reached straigh away
    def __init__(self, aColour, aSteps, aStartK = 0):
        # Calculate start colour
        self.__colour = (self.__GetValidColour(aColour[0]*aStartK), 
                         self.__GetValidColour(aColour[1]*aStartK),
                         self.__GetValidColour(aColour[2]*aStartK))
        # Calculate deltas
        self.__dr = aColour[0]/aSteps
        self.__dg = aColour[1]/aSteps
        self.__db = aColour[2]/aSteps

    #---------------------------------------------------------------------------
    # Returns a valid colour from a given value
    def __GetValidColour(self, aVal):
        return int(0 if aVal < 0 else (255 if aVal > 255 else aVal))

    #---------------------------------------------------------------------------
    # Returns current colour
    def GetCurrentColour(self):
        return self.__colour
        
    #---------------------------------------------------------------------------
    # Returns next colour
    def GetNextColour(self):
        # Result value
        c = self.__colour
        # Increment the colour
        self.__colour = (self.__GetValidColour(c[0] + self.__dr),
                         self.__GetValidColour(c[1] + self.__dg),
                         self.__GetValidColour(c[2] + self.__db))
        return c
#-------------------------------------------------------------------------------

#===============================================================================
# Image collection
#===============================================================================
class CImageCollection:
    #--------------------------------------------------------------
    def __init__(self, aImagesLocationPath):
        self.__location = aImagesLocationPath;
        self.Images = []

    #--------------------------------------------------------------
    def __getitem__(self, key):
        return self.Images[key]        
        
    #--------------------------------------------------------------
    # Loads image located collection's location into the collection
    # Returns False if failed
    def Load(self, aFileName):
        fileName = os.path.join(self.__location, aFileName)
        try:
            image = pygame.image.load(fileName)
            self.Images.append(image)
        except pygame.error, message:
            print "!!! Cannot load explosion image from " + fileName
            # Add dummy image to avoid breaking the program
            self.Images.append(pygame.Surface((20, 20)))
    

#-------------------------------------------------------------------------------
