class GameBase(Runnable):
    components = GameComponent
    canvas = Canvas
    thread = Thread
    dbg = Graphics
    db_image = BufferedImage
    
    running = False
    is_paused = False
    game_over = False
    is_applet = False
    size_changed = False
    game_time = GameTime()
    updates = 0
    
    NO_DELAYS_PER_YIELD = 16
    MAX_FRAME_SKIPS = 5
    period = None
    game_start_time = None
    frames_skipped = None
    
    gelapsed_before = System.nanoTime()
    gelapsed_after = System.nanoTime()
    
    MAX_STAT_INTERVAL = 1
    NUM_FPS = 10
    stats_interval = 0
    prev_stats_time = 0
    total_elapsed_time = 0
    time_spend_in_game = 0
    frame_count = 0
    fps_store = []
    stats_count = 0
    average_fps = 0
    total_frames_skipped = 0
    ups_store = 0
    average_ups = 0
    df = DecimalFormat("0.##")


    def set_size(self, size):
        self.canvas.setSize(size)
        self.size_changed = True


    def set_resolution(self, size):
        self.set_size(size)


    def get_resolution(self):
        return Dimension(self.db_image.getWidth(), self.db_image.getHeight())


    def get_is_active(self):
        if self.is_paused == True:
            return False
        else:
            return True


    def get_is_applet(self):
        return self.is_applet


    def set_is_applet(self, flag):
        if type(flag) is not type(True):
            raise Exception("Flag passed to set_is_applet not a boolean. Got %s instead." % type(flag))
        self.is_applet = flag


    def get_stats_avg_fps(self):
        return self.average_fps


    def get_stats_avg_ups(self):
        return self.average_ups


    def __init__(self, size, fps):
        self.set_size(size)
        Component.setPreferredSize(size)
        Component.setMinimumSize(size)
        Component.setMaximumSize(size)
        
        Component.setBackground(Color.white)
        
        Component.setFocusable(True)
        Component.requestFocus()
        
        db_image = BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB)
        
        self.fps_store = self.NUM_FPS
        self.ups_store = self.NUM_FPS
        i = 0
        if i < self.NUM_FPS:
            self.fps_store[i] = 0
            self.ups_store[i] = 0
            i += 1


    def run(self):
        before_time = None
        after_time = None
        time_diff = None
        sleep_time = None
        over_sleep_time = 0
        no_delays = 0
        excess = 0
        
        game_start_time = System.nanoTime()
        prev_stats_time = game_start_time
        before_time = game_start_time
        
        running = True
        
        while running:
            self.game_update()
            self.game_render()
            self.paint_screen()
            
            after_time = System.nanoTime()
            time_diff = after_time - before_time
            sleep_time = (self.period - time_diff) - over_sleep_time
            
            if sleep_time > 0:
                try:
                    Thread.sleep(sleep_time)
                except InterruptedException as e:
                    pass
                over_sleep_time = (System.nanoTime() - after_time) - sleep_time
            else:
                excess -= sleep_time
                over_sleep_time = 0
                
                if (no_delays + 1) >= self.NO_DELAYS_PER_YIELD:
                    Thread.yield()
                    no_delays = 0
            
            before_time = System.nanoTime()
            
            skips = 0
            
            while excess > self.period and skips < self.MAX_FRAME_SKIPS:
                excess -= self.period
                self.game_update()
                skips += 1
            
            self.frames_skipped += skips
            
            self.store_stats()
        
        self.print_stats()
        System.exit(0)


    def store_stats(self):
        self.frame_count += 1
        self.stats_interval += self.period
        
        if self.stats_interval >= self.MAX_STAT_INTERVAL:
            time_now = System.nanoTime()
            self.time_spend_in_game = time_now - self.game_start_time
            
            real_elapsed_time = time_now - self.prev_stats_time
            self.total_elapsed_time += real_elapsed_time
            
            self.total_frames_skipped += self.frames_skipped
            
            if self.total_elapsed_time > 0:
                actual_fps = self.frame_count / self.total_elapsed_time
                actual_ups = (self.frame_count + self.total_frames_skipped) / self.total_elapsed_time
            
            self.fps_store[self.stats_count % self.NUM_FPS] = actual_fps
            self.ups_store[self.stats_count % self.NUM_FPS] = actual_ups
            self.stats_count += 1
            
            i = 0
            if i < self.NUM_FPS:
                total_fps = self.fps_store[i]
                total_ups = self.ups_store[i]
                i += 1
            
            if self.stats_count < self.NUM_FPS:
                self.average_fps = total_fps / self.stats_count
                self.average_ups = total_ups / self.stats_count
            else:
                self.average_fps = total_fps / self.NUM_FPS
                self.average_ups = total_ups / self.NUM_FPS
            
            self.frames_skipped = 0
            self.prev_stats_time = time_now
            self.stats_interval = 0


    def game_update(self):
        self.gelapsed_after = System.nanoTime()
        
        self.game_time.elapsed_game_time.set_span(self.gelapsed_before, self.gelapsed_after)
        self.game_time.elapsed_real_time.set_span(self.gelapsed_before, self.gelapsed_after)
        
        self.game_time.total_game_time.set_span(self.game_start_time, self.gelapsed_after)
        self.game_time.total_real_time.set_span(self.game_start_time, self.gelapsed_after)
        
        self.gelapsed_before = System.nanoTime()
        
        if self.running and self.is_paused is not True and self.game_over is not True:
            for item in self.components.getComponents():
                item.update(self.game_time)
            self.updates += 1


    def get_render(self):
        if self.db_image is None or self.size_changed:
            size = Dimension(Component.getWidth(), Component.getHeight())
            self.set_size(size)
            Component.setPreferredSize(size)
            Component.setMinimumSize(size)
            Component.setMaximumSize(size)
            self.size_changed = False
            
            try:
                self.db_image = BufferedImage(Component.getWidth(), Component.getHeight(), BufferedImage.TYPE_INT_RGB)
            except JavaException as e:
                self.db_image = None
                System.out.println("Render Error: %s" % e)
                System.out.println("Render Error: Buffer not initialized properly")
                System.out.println("Render Error: Resolving...")


    def paint_screen(self):
        bs = Canvas.getBufferStrategy()
        if bs is None:
            Canvas.createBufferStrategy(3)
        
        g = bs.getDrawGraphics()
        g.drawImage(self.db_image, 0, 0, Component.getWidth(), Component.getHeight(), None)
        g.dispose()
        bs.show()


    def start_game(self):
        if self.running:
            return
        self.thread = Thread(self)
        self.thread.start()
        self.running = True


    def stop_game(self):
        if self.running is None:
            return
        self.thread.stop()
        self.running = False


    def set_preferred_fps(self, fps):
        self.period = 1000/fps


    def reset_elapsed_time(self):
        self.game_time.elapsed_game_time.set_span(0)
        self.game_time.elapsed_real_time.set_span(0)


    def add_component(self, game_component):
        game_component.initialize()
        game_component.load_content()
        self.components.add(game_component)


    def remove_component(self, game_component):
        game_component.unload_content()
        self.components.remove(game_component)


    def resume_game(self):
        self.is_paused = False


    def pause_game(self):
        self.is_paused = True


    def print_stats(self):
        System.out.println("Frame Count/Loss: %s / %s" % (self.frame_count, self.total_frames_skipped))
        System.out.println("Average FPS: %s" % self.df.format(self.average_fps))
        System.out.println("Average UPS: %s" % self.df.format(self.average_ups))
        System.out.println("TIme Spend: %s secs" % self.time_spend_in_game)
        System.out.println("Total Updates: %s" % self.updates)
        System.out.println("dbImage: %s" % self.db_image.toString())