###############################################################################
# File:        guTools.py
# Appointment: Different helpers
# Project:     GalaxyU
# Author:      AR
# History:
# 26.02.2015 Added catching unknown exception in MoveImage (fixing windows related hanging bug)
# 10.11.2013 Added CHighlightedSpaceObject
# 03.11.2013 Created
###############################################################################
import wx
import math
import pygame
import pygame.gfxdraw

import guApp
import wxTools

#===============================================================================
# gu wrapper of wxTools.CCfgFrame
#===============================================================================
class CCfgFrame(wxTools.CCfgFrame):
    #---------------------------------------------------------------------------
    # aCfg - config object
    # aCfgPath - section path where to save data
    # aCfgName - subsection name for the frame
    def __init__(self, parent, aCfg, aCfgPath, aCfgName):
        wxTools.CCfgFrame.__init__(self, parent, aCfg, aCfgPath, aCfgName)

        # Focus event
        self.Bind(wx.EVT_ACTIVATE, self.OnActivate)

        # Unregister itself when closing        
        self.OnSaveCfg = lambda: guApp.Application.WindowsCollection.Unregister(self)

    #---------------------------------------------------------------------------
    def OnActivate(self, e):
        guApp.Application.WindowsCollection.Update(self)
        
#-------------------------------------------------------------------------------


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Lazy evaluated via aGetObjFunc container of objets with 2 keys
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def GetObject(aCont, aKey1, aKey2, aObjectType, aGetObjFunc):
    # Find sub container by 1st key
    if aKey1 not in aCont:
        aCont[aKey1] = {}
    if aKey2 not in aCont[aKey1]:
        aCont[aKey1][aKey2] = {}
    if aObjectType not in aCont[aKey1][aKey2]:
        aCont[aKey1][aKey2][aObjectType] = aGetObjFunc()
    return aCont[aKey1][aKey2][aObjectType]
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Adds an object of type aObjectType with coordinates X,Y to claster container
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def AddObjectToClaster(aCont, aFactor, aObject, aObjectType):
    x = (int(aObject.X)/aFactor)*aFactor
    y = (int(aObject.Y)/aFactor)*aFactor
    if x not in aCont:
        aCont[x] = {}
    if y not in aCont[x]:
        aCont[x][y] = {}
    if aObjectType not in aCont[x][y]:
        aCont[x][y][aObjectType] = []
    aCont[x][y][aObjectType].append(aObject)
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<



#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Draws nation flag on pygamne surface aScreen for owner in coordinates aX,aY
# aStateColour specifies border and pole colours
# aPoleOnLeft - if True, the pole is drawn on the left side, otherwise - on the right
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def DrawNationFlag(\
        aScreen, aOwner, aX, aY, aStateColour,\
        aPoleOnLeft = True, aFlagImage = None):
    if aOwner != "":
        flag = aFlagImage \
            if aFlagImage is not None \
            else guApp.Application.GetReport().GetNationFlagImage(aOwner)

        # Draw it            
        flagrect = flag.get_rect()
        flagrect.centerx = aX + flagrect.width/2
        flagrect.centery = aY - flagrect.height 
        aScreen.blit(flag, flagrect)

        # Draw a border around the flag
        borderRect = flagrect
        borderRect.width += 4
        borderRect.height += 4
        borderRect.centerx -= 2
        borderRect.centery -= 2
        pygame.gfxdraw.rectangle(aScreen, borderRect, aStateColour)
        # Draw a flag pole
        x = borderRect.left if aPoleOnLeft else borderRect.right
        pygame.draw.line(aScreen, aStateColour,
                         (x, borderRect.bottom),
                         (x, borderRect.bottom + int(borderRect.height/1.7)))
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Moves image on a pygame viewer from aPos1 to aPos2
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def MoveImage(aViewer, aImage, aBkGround, aPos1, aPos2, aSpeed = 1, aMoveWhileVisible = False, aTrackSize = 0):
    try:
        clock = pygame.time.Clock()
        print aPos1, "--->", aPos2
        rect = aImage.get_rect()
        rect.centerx = aPos1[0]
        rect.centery = aPos1[1]
        bkrect = aBkGround.get_rect()
        dx = float(aPos2[0] - aPos1[0])
        dy = float(aPos2[1] - aPos1[1])
        if dx != 0 or dy != 0:
            m = max(abs(dx), abs(dy))
            dx /= m
            dy /= m
            dx *= aSpeed
            dy *= aSpeed
            
            x = float(rect.centerx)
            y = float(rect.centery)
            
            lessX = rect.centerx < aPos2[0] 
            lessY = rect.centery < aPos2[1]
            trackCounter = 0 
            while aViewer.IsRectOnScreen(rect) and \
                    True if aMoveWhileVisible else ((x < aPos2[0] if lessX else x > aPos2[0]) or \
                                                   (y < aPos2[1] if lessY else y > aPos2[1])):
                clock.tick(200)
                trackCounter += 1
                if trackCounter > aTrackSize:
                    aViewer.Screen.blit(aBkGround, bkrect)
                    trackCounter = 0
                aViewer.Screen.blit(aImage, rect)
                pygame.display.flip()
                x += dx
                y += dy
                rect.centerx = x
                rect.centery = y
    except:
        # By some unknown reason exception is happening on windows frozen build
        print 'Unknown exception in MoveImage'
        
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Shows explosion on a pygame screen aScreen
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def ShowExplosion(aScreen, aBkGround, aPos, aSize, aSpeed = 20):
    clock = pygame.time.Clock()
    bkrect = aBkGround.get_rect()
    for image in guApp.Application.ExplosionImages.Images:
        scaledImage = pygame.transform.scale(image, (aSize, aSize))
        clock.tick(aSpeed)
        aScreen.blit(aBkGround, bkrect)
        rect = scaledImage.get_rect()
        rect.centerx = aPos[0]
        rect.centery = aPos[1]
        aScreen.blit(scaledImage, rect)
        pygame.display.flip()
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Shows shield  on a pygame screen aScreen
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def ShowShield(aScreen, aBkGround, aPos, aRadius, aColour, aIterations = 5, aSpeed = 30):
    clock = pygame.time.Clock()
    bkrect = aBkGround.get_rect()
    for i in range(aIterations):
        clock.tick(aSpeed)
        aScreen.blit(aBkGround, bkrect)
        pygame.draw.circle(aScreen, aColour, aPos, aRadius, 1)
        pygame.display.flip()
        clock.tick(aSpeed)
        aScreen.blit(aBkGround, bkrect)
        pygame.display.flip()
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# Shows smoke
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def ShowSmoke(aScreen, aImage, aBkGround, aPos, aSize, aSpeed = 100):
    clock = pygame.time.Clock()
    bkrect = aBkGround.get_rect()
    n = 10
    d = aSize/n
    sz = d*n/2
    for i in range(n):
        sz += d if i <= n/2 else (-d)
        scaledImage = pygame.transform.scale(aImage, (sz, sz))
        clock.tick(aSpeed)
        aScreen.blit(aBkGround, bkrect)
        rect = scaledImage.get_rect()
        rect.centerx = aPos[0]
        rect.centery = aPos[1]
        aScreen.blit(scaledImage, rect)
        pygame.display.flip()
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


#===============================================================================
# Highlight a space object on a screen and status bar
#===============================================================================
class CHighlightedSpaceObject(wxTools.CFlexDrawBase):
    #-----------------------------------------------------------------------
    # aParent - window object
    # x,y - initial coordinates
    # aStatusBarFunc(string) - displays a text
    def __init__(self, aParent, aX, aY, aSpaceObject, aDiameter, aStatusBarFunc):
        wxTools.CFlexDrawBase.__init__(self, aParent, aX, aY)
        # Store star and radious on the screen        
        self.SpaceObject = aSpaceObject
        self.__radius = aDiameter/2
        self.__pgDisplay = aParent
        self.__statusBarFunc = aStatusBarFunc
        
    #-----------------------------------------------------------------------
    def __del(self):
        pass

    #-----------------------------------------------------------------------
    # Updates status bar by space object - if None - resets
    def __UpdateStatusBar(self, aSpaceObject):
        self.__statusBarFunc(aSpaceObject.GetDescription() if aSpaceObject is not None else "")

    #-----------------------------------------------------------------------
    def Draw(self):
        self.GetDC().DrawCircle(self.StartX, self.StartY, self.__radius)
        self.__UpdateStatusBar(self.SpaceObject)

    #---------------------------------------------------------------------------
    # Redefined virtual from 
    def ClearOld(self):
        self.Draw()
        self.__UpdateStatusBar(None)
#-------------------------------------------------------------------------------
