import os

from . import logger


class Context:
    __slots__ = ('blender',
                 'device_type',
                 'device_name',
                 'device_single',
                 'scenes',
                 'scenes_dir',
                 'configure_script',
                 'image_output_dir',
                 'single_compute_scene')

    def __init__(self):
        # Full path to blender binary.
        self.blender = "blender"
        # Type of the device to run on. It must be either CPU, CUDA or OpenCL.
        self.device_type = 'CPU'
        # Name of the device to render on.
        self.device_name = 'NAME'
        # Use single device when there are multiple one matching the name
        self.device_single = False
        # By default we use empty list, it is up to the user to fill it in.
        self.scenes = []
        # It is up to the user to provide proper path to scenes.
        self.scenes_dir = ""
        # Blender-side configuration script.
        self.configure_script = "configure.py"
        # Directory where render result images will be saved.
        # Empty means no results are saved.
        self.image_output_dir = ""
        # There is only one file for each of compute device types, which will
        # do some post-load setup for compute device and tile size.
        self.single_compute_scene = False

    def listAllScenes(self, directory):
        import os
        if not os.path.exists(directory):
            logger.ERROR("Non-exiting directory {}" . format(directory))
            return []
        if not os.path.isdir(directory):
            logger.ERROR("Not a directory {}" . format(directory))
            return []
        all_scenes = sorted(os.listdir(directory))
        usable_scenes = []
        for scene in all_scenes:
            scene_filename = self.getSceneFilename(scene, do_checks=False)
            if os.path.exists(scene_filename) and \
               os.path.isfile(scene_filename):
                usable_scenes.append(scene)
        return usable_scenes

    def printSummary(self):
        logger.INFO("Benchmark summary:")
        logger.INFO("  Device type: {}" . format(self.device_type))
        if self.device_name:
            logger.INFO("  Device name: {}" . format(self.device_name))
        logger.INFO("  Scenes: {}" . format(", ".join(self.scenes)))

    def verify(self):
        if not os.path.exists(self.blender):
            logger.ERROR("Missing blender: {}" . format(self.blender))
            return False
        if not os.path.isfile(self.blender):
            logger.ERROR("Blender is not a file: {}" . format(self.blender))
            return False
        if not os.path.exists(self.configure_script):
            logger.ERROR("Missing configuration script: {}" .
                         format(self.configure_script))
            return False
        if not os.path.isfile(self.configure_script):
            logger.ERROR("Configuration script is not a file: {}" .
                         format(self.configure_script))
            return False
        if self.image_output_dir:
            if not os.path.exists(self.image_output_dir):
                logger.ERROR("Missing image output directory: {}" .
                             format(self.image_output_dir))
                return False
            if not os.path.isdir(self.image_output_dir):
                logger.ERROR("Image out is not a directory: {}" .
                             format(self.image_output_dir))
                return False
        return True

    def getDeviceFileSuffix(self):
        if self.single_compute_scene:
            return ""
        elif self.device_type == 'CPU':
            return '_cpu'
        elif self.device_type in ('CUDA', 'OPENCL', 'GPU'):
            return '_gpu'
        else:
            logger.FATAL("Unknown device type: {}" . format(self.device_type))
        return ""

    def getSceneFilename(self, scene, do_checks=True):
        suffix = self.getDeviceFileSuffix()
        blendfile = scene + suffix + ".blend"
        filepath = os.path.join(self.scenes_dir, scene, blendfile)
        if do_checks:
            if not os.path.exists(filepath):
                logger.FATAL("File not file: {}" . format(filepath))
            if not os.path.isfile(filepath):
                logger.FATAL("Scene is not a file: {}" . format(filepath))
        return filepath
