from __future__ import division

import pygame, math, sys, random, utils, simobject, os, ui, constants
from pygame.locals import *

#os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0,0)

class Layer:
    def __init__(self, spriteGroup, depth):
        self.spriteGroup = spriteGroup
        self.depth = depth
        
    def __cmp__(self, other):
        return cmp(self.depth, other.depth)

class Engine(object):
    
    def __init__(self):
        """ initialize the game engine"""
        #os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0,0)
        pygame.init()
        pygame.mixer.init()
        
        ''' sets up the screen'''
        
        self.screen = pygame.display.set_mode(constants.SCREEN_PROP[0], constants.SCREEN_PROP[1])
        self.get_screen_dim()
        
        ''' sets up a blank background'''
        self.background = pygame.Surface(self.screen.get_size())
        self.background.fill((255,255,255))

        self.define_sprite_groups()
        
        self.set_clock_rate(100)
        
        """ setup return state """
        self.state = None
        
        self.draw_overlay_bool = True
        
    def set_clock_rate(self, value):
        ''' limits the fps to stop the game from running too fast'''
        self.fps_cap = value
        """best to keep dt_min and phys_dt synchronised, or else main character "skips" about - annoying. don't know why."""
        ''' limits the maximum time interval used in the game simulation to stop the physics calcs from killing the game'''
        self.dt_min = 1.0/value
        ''' limits the maximum time interval used in the physics simulation to reduce physics errors'''
        self.physics_dt = 1.0/value
        '''provides an initial value for self.dt'''
        self.dt = self.fps_cap/1000.0
        
    def get_screen_dim(self):
        """need to remove crappy vars and replace screen_center with a function"""
        self.screen_rect = self.screen.get_rect()
        self.screen_width = self.screen.get_width()
        self.screen_height = self.screen.get_height()
        self.screen_dim = (self.screen_width,self.screen_height)
        self.screen_center = (self.screen_width/2,self.screen_height/2)
    
    def define_sprite_groups(self):
        '''creates some containers for sprite objects, simObjects and UIelements'''

        # we do not layer this group = this is used for close range collision detection, etc
        self.spriteGroups = {}
        
        self.textsprites = []
        self.imagesprites = []
        self.sprites = []
        
        self.spriteGroups[-3] = self.make_sprite_group(self.textsprites)
        self.spriteGroups[-2] = self.make_sprite_group(self.imagesprites)
        self.spriteGroups[-1] = self.make_sprite_group(self.sprites)

        
        # these groups are used for drawing in layers.
        self.layers = []
                
        self.make_sprite_layer([], 0)
        self.make_sprite_layer([], 1)
        self.make_sprite_layer([], 2)
        self.make_sprite_layer([], 997)
        self.make_sprite_layer([], 998)
        self.make_sprite_layer([], 999)
        self.make_sprite_layer([], 1000)

        
    def start(self):
        """begins the main loop"""
        self.clock = pygame.time.Clock()
        self.continue_running = True
        while self.continue_running:
            self.__mainLoop()
        """ when self.continue_running is False, we exit out of this State """
        return self.return_state()
        
    def stop(self):
        """stops the loop"""
        self.continue_running = False
        
    def draw_overlay(self):
        pass
        
    def __mainLoop(self):
        """ manage all the main events automatically called by start"""
        
        ''' finds the amount of time to be passed to the simulations'''
        if self.dt_min == 0:
            self.dt = self.clock.tick(self.fps_cap)/1000.0
        else:
            self.dt = min(self.dt_min,self.clock.tick(self.fps_cap)/1000.0)
            
            
        ''' captures events (from player, etc) '''
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.continue_running = False
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    self.continue_running = False
            self.events(event)
        
        self.events(None)
        
        
        """ calls the update function from the game module (creates sprites 
        and adds them to sprite groups, gets user input, etc)"""
        self.update()
        
        """updates all sprites"""
        
        self.spriteGroups[-1].update() #for updating simulation objects
        self.spriteGroups[-2].update() #for updating image objects
        self.spriteGroups[-3].update() #for updating text
        
        """ We set the state of the game here, to control what follows after this state ends"""
        self.set_state()
        
        """ Here we draw everything """
        """ screen fill ensures we have a color for every pixel"""
        
        for layer in self.layers:
            """ draws sprites in layers """
            if layer.depth<1000:
                layer.spriteGroup.draw(self.screen)
        
        if self.draw_overlay_bool:
            """ here we draw things on top of sprites, like bars, paths, etc """
            for sim in self.spriteGroups[-1]:
                sim.draw_overlay()
            
            """ draws lines, etc on top of sprites """
            self.draw_overlay()
        
        """ finally we draw the UI """
        self.spriteGroups[1000].draw(self.screen)
        
        """refreshes the screen"""
        pygame.display.flip()
        
    def make_sprite_layer(self, sprites, i):
        """ returns a sprite group layer at height i of the list of sprites"""
        self.spriteGroups[i] = pygame.sprite.Group(sprites)
        self.addLayer(Layer(self.spriteGroups[i], i))
        
    def make_sprite_group(self, sprites):
        """ returns a sprite group """
        return pygame.sprite.Group(sprites)
        
    
    def addLayer(self, layer):
        self.layers.append(layer)
        self.layers.sort()
    
    def events(self, event):
        """ for event handling """
        pass

    def update(self):
        """ for updating the game """
        """ we fill the screen in the absence of anything else"""
        self.screen.fill((50,50,50))

    def set_caption(self, title):
        """ set the window title text """
        pygame.display.set_caption(title)
    
    def set_state(self):
        pass

    def return_state(self):
        return self.state
