import pygame
import sys
import os
from collections import namedtuple
import time
import resourcemanager

ColorList = namedtuple("ColorList", "black white red green blue")
colors = ColorList((0,0,0),(0xFF,0xFF,0xFF),(0xFF,0,0),(0,0xFF,0),(0,0,0xFF))

PyListener = namedtuple("PyListener", "condition effect")
PyEventListener = namedtuple("PyEventListener","events condition effect")


    

class Pyengine:
    def __init__(self,size):
        pygame.init()
        self.__size = size
        self.__fps = 60
        self.__bg = colors.white
        self.__fg = colors.black
        self.__on_update = []
        self.__on_draw = []
        self.__keys_down = {}
        self.__listeners = []
        self.__event_handlers = []
        self.__mouse_down = {}
        self.__display = None
        self.__screen_centerX = size[0]/2
        self.__scaleX = 1.0
        self.__scaleY = 1.0
        self.__screen_centerY = size[1]/2
        self.__clock = pygame.time.Clock()
        self.__buffer_surface = None
        self.__resource_manager = resourcemanager.ResourceManager()
        self.__animators = {}
    def add_animator(self,name,animator):
        self.__animators[name] = animator
    def remove_animator(self,name):
        del self.__animators[name]
    def get_animator(self,name):
        return self.__animators[name]
    def set_scale_x(self,x):
        self.__scaleX = x
    def get_scale_x(self):
        return self.__scaleX
    def set_scale_y(self,y):
        self.__scaleY = y
    def get_scale_y(self):
        return self.__scaleY
    def set_scale(self,s):
        self.__scaleX = s[0]
        self.__scaleY = s[1]
    def get_scale(self):
        return (self.__scaleX,self.__scaleY)
    def set_fg(self,fg):
        self.__fg = fg
    def get_fg(self):
        return self.__fg
    def set_bg(self,bg):
        self.__bg = bg
    def get_bg(self):
        return self.__bg
    def get_display(self):
        return self.__display()
    def set_screen_center_x(self,x):
        self.__screen_centerX = x
    def get_screen_center_x(self):
        return self.__screen_centerX
    def set_screen_center_y(self,y):
        self.__screen_centerY = y
    def get_screen_center_y(self):
        return self.__screen_centerY
    def set_screen_center(self,pos):
        self.__screen_centerX = pos[0]
        self.__screen_centerY = pos[1]
    def get_screen_center(self):
        return (self.__screen_centerX,self.__screen_centerY)
    def get_buffer_surface(self):
        return self.__buffer_surface
    def get_resource_manager(self):
        return self.__resource_manager

    def update_all_animators(self):
        ms = self.__clock.get_time()
        for i in self.__animators:
            self.__animators[i].update(ms)
    def draw_all_animators(self):
        for i in self.__animators:
            self.draw_image(self.__animators[i].get_current_image(),self.__animators[i].get_position())



    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.exit()
            elif event.type == pygame.KEYDOWN:
                self.__keys_down[event.key] = True
            elif event.type == pygame.KEYUP:
                self.__keys_down[event.key] = False
            elif event.type == pygame.MOUSEBUTTONDOWN:
                self.__mouse_down = True
            elif event.type == pygame.MOUSEBUTTONUP:
                self.__mouse_down = False
            for handler in self.__event_handlers:
                if event.type in handler.events and handler.condition(self,event):
                    handler.effect(self,event)

    def draw_image(self,name,pos):
        self.__buffer_surface.blit(self.__resource_manager.get_image(name),pos)

    def is_key_down(self,key):
        if not key in self.__keys_down:
            return False
        return  self.__keys_down[key]
    
    def is_mouse_button_down(self,button):
        if not button in self.__mouse_down:
            return False
        return self.__mouse_down[button]

    def run(self):
        screen = pygame.display.set_mode(self.__size)
        self.__display = screen
        oldTime = time.time()
        while True:
            spf = 1.0 / self.__fps
            self.handle_events()
            self.update()
            self.draw(screen)
            self.__clock.tick(self.__fps)
            
    
    def exit(self):
        pygame.display.quit()
        pygame.quit()
        sys.exit()
    def update(self):
        self.update_all_animators()
        for l in self.__listeners:
            if l.condition(self):
                l.effect(self)            
    def draw(self,display):
        self.__buffer_surface = pygame.Surface(display.get_size())
        display.fill(colors.red)
        self.__buffer_surface.fill(self.__bg)
        for od in self.__on_draw:
            od(self,self.__buffer_surface)
        self.draw_all_animators()
        src_size = (self.__size[0]/self.__scaleX,self.__size[1]/self.__scaleY)
        top = self.__screen_centerY - src_size[1] / 2 
        left = self.__screen_centerX - src_size[0] / 2
        cropped = pygame.Surface(src_size)

        cropped.blit(self.__buffer_surface,(0,0),(left,top,src_size[0],src_size[1]))
        cropped = pygame.transform.scale(cropped,self.__size)
        display.blit(cropped,(0,0))
        pygame.display.update((0,0,self.__size[0],self.__size[1]))
    
    def add_draw_listener(self,f):
        self.__on_draw.append(f)
    def add_listener(self,condition,effect):
        self.__listeners.append(PyListener(condition,effect))
    def add_on_update(self,effect):
        self.__add_listener(lambda s:True,effect)
    def add_event_listener(self,events,condition,effect):
        self.__event_handlers.append(PyEventListener(events,condition,effect))
    def set_fps(self,fps):
        self.__fps = fps
    def get_fps(self):
        return self.__fps

    