def __init__(self, filename):
        self._pak = Pak(filename)

        # loaded sprites (with image data loaded in RAM)
        self._sprites = dict()
        # textures loaded in VRAM (texture index -> texture, postiion)
        self._textures = dict()
class PakManager:
    def __init__(self, filename):
        self._pak = Pak(filename)

        # loaded sprites (with image data loaded in RAM)
        self._sprites = dict()
        # textures loaded in VRAM (texture index -> texture, postiion)
        self._textures = dict()

    def __del__(self):
        self._pak.close()

    def __getitem__(self, index):
        # make sure the texture is loaded and return it
        return self.load(index)

    def load(self, index):
        # load the texture (if not already loaded) and return it
        #
        # index meaning:
        # --------------
        # with crop: 256 + sprite_index * 256 + frame_index
        # without crop: sprite_index
        #
        # WARNING: recent change, an entire image return a list of frame
        # return the texture if already loaded
        if index in self._textures:
            return self._textures[index]

        # entire image
        if index < 256:
            sprite_index = index

            # load the sprite (if not already done) and get it
            sprite = self._load_sprite(sprite_index)
            sprite.image.create_mask_from_color(sprite.color)

            texture = sf.Texture.from_image(sprite.image)

            position = []
            for frame in sprite:
                position.append(frame)

        # crop image
        else:
            sprite_index = (index - 256) // 256
            frame_index = index % 256

            # load the sprite (if not already done) and get it
            sprite = self._load_sprite(sprite_index)

            x, y, w, h, offset = sprite.frames[frame_index]
            texture = sf.Texture.from_image(sprite.image, (x, y, w, h))
            position = offset

        self._textures[index] = (texture, position)
        return self._textures[index]

    def unload(self, index):
        del self._textures[index]

    def free_memory(self):
        self._sprites.clear()

    def _load_sprite(self, index):
        # load a sprite (if not already loaded) and return it
        if index not in self._sprites:
            self._sprites[index] = self._pak[index].load()

        return self._sprites[index]