# -*- coding: utf8 -*-
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
# --------------------------------------------------------------------------
# Blender 2.5 LuxRender Add-On
# --------------------------------------------------------------------------
#
# Authors:
# Simon Wendsche
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# ***** END GPL LICENCE BLOCK *****
#

import math

import pyluxcore
from ...outputs.luxcore_api import ToValidLuxCoreName

from .utils import convert_texture_channel, generate_volume_name


class VolumeExporter(object):
    def __init__(self, luxcore_exporter, blender_scene, volume):
        self.luxcore_exporter = luxcore_exporter
        self.blender_scene = blender_scene
        self.volume = volume

        self.properties = pyluxcore.Properties()
        self.luxcore_name = ''


    def convert(self):
        # Remove old properties
        self.properties = pyluxcore.Properties()

        self.__convert_volume()

        return self.properties


    def __generate_volume_name(self, name):
        # materials and volumes must not have the same names
        self.luxcore_name = generate_volume_name(name)

    
    def __convert_volume(self):
        volume = self.volume
        self.__generate_volume_name(volume.name)
        prefix = 'scene.volumes.' + self.luxcore_name
    
        try:
            def absorption_at_depth_scaled(abs_col):
                for i in range(len(abs_col)):
                    v = float(abs_col[i])
                    depth = volume.depth
                    scale = volume.absorption_scale
                    abs_col[i] = (-math.log(max([v, 1e-30])) / depth) * scale * (v == 1.0 and -1 or 1)
    
            print('Converting volume: %s' % volume.name)
    
            # IOR Fresnel
            if volume.fresnel_usefresneltexture:
                ior_val = convert_texture_channel(self.luxcore_exporter, self.properties, self.luxcore_name, volume, 'fresnel', 'fresnel')
            else:
                ior_val = volume.fresnel_fresnelvalue
    
            # Absorption
            attribute = 'absorption' if volume.type == 'clear' else 'sigma_a'
            absorption_color = getattr(volume, attribute + '_color')
            is_textured = getattr(volume, attribute + '_usecolortexture')

            if is_textured:
                abs_col = convert_texture_channel(self.luxcore_exporter, self.properties, self.luxcore_name, volume, attribute, 'color')

                if volume.absorption_scale != 1.0:
                    scale_name = self.luxcore_name + '_absorptionscaling'
                    self.properties.Set(pyluxcore.Property('scene.textures.' + scale_name + '.type', ['scale']))
                    self.properties.Set(pyluxcore.Property('scene.textures.' + scale_name + '.texture1', volume.absorption_scale))
                    self.properties.Set(pyluxcore.Property('scene.textures.' + scale_name + '.texture2', abs_col))
                    abs_col = scale_name
            else:
                abs_col = list(absorption_color)
                absorption_at_depth_scaled(abs_col)

            self.properties.Set(pyluxcore.Property(prefix + '.absorption', abs_col))
            self.properties.Set(pyluxcore.Property(prefix + '.type', [volume.type]))
            self.properties.Set(pyluxcore.Property(prefix + '.ior', ior_val))
            self.properties.Set(pyluxcore.Property(prefix + '.priority', volume.priority))

            # Light emission
            if volume.use_emission:
                emission_color = convert_texture_channel(self.luxcore_exporter, self.properties, self.luxcore_name, volume, 'emission', 'color')

                if volume.emission_usecolortexture:
                    if volume.gain != 1.0:
                        # Use a scale texture to multiple the textured emission with the gain
                        scale_name = self.luxcore_name + '_emissionscale'
                        self.properties.Set(pyluxcore.Property('scene.textures.' + scale_name + '.type', ['scale']))
                        self.properties.Set(pyluxcore.Property('scene.textures.' + scale_name + '.texture1', emission_color))
                        self.properties.Set(pyluxcore.Property('scene.textures.' + scale_name + '.texture2', volume.gain))
                        emission_color = scale_name
                else:
                    # Emission is not textured, just multiply r,g,b with the gain
                    emission_color[:] = [i * volume.gain for i in emission_color]

                self.properties.Set(pyluxcore.Property(prefix + '.emission', emission_color))

            if volume.type in ['homogeneous', 'heterogeneous']:
                # Scattering color
                if volume.sigma_s_usecolortexture:
                    scattering_col = convert_texture_channel(self.luxcore_exporter, self.properties, self.luxcore_name, volume, 'sigma_s', 'color')
    
                    if volume.scattering_scale != 1.0:
                        self.properties.Set(pyluxcore.Property('scene.textures.' + self.luxcore_name + '_scatterscaling.type', ['scale']))
                        self.properties.Set(pyluxcore.Property('scene.textures.' + self.luxcore_name + '_scatterscaling.texture1',
                                                             volume.scattering_scale))
                        self.properties.Set(pyluxcore.Property('scene.textures.' + self.luxcore_name + '_scatterscaling.texture2', scattering_col))
                        s_col = self.luxcore_name + '_scatterscaling'
                    else:
                        s_col = scattering_col
                else:
                    s_col = [volume.sigma_s_color.r * volume.scattering_scale,
                             volume.sigma_s_color.g * volume.scattering_scale,
                             volume.sigma_s_color.b * volume.scattering_scale]
    
                self.properties.Set(pyluxcore.Property(prefix + '.scattering', s_col))
                self.properties.Set(pyluxcore.Property(prefix + '.asymmetry', list(volume.g)))
                self.properties.Set(pyluxcore.Property(prefix + '.multiscattering', [volume.multiscattering]))
    
            if volume.type == 'heterogeneous':
                self.properties.Set(pyluxcore.Property(prefix + '.steps.size', volume.stepsize))
        except Exception as err:
            print('Volume export failed, skipping volume: %s\n%s' % (volume.name, err))
            import traceback
    
            traceback.print_exc()
    
            # define a clear volume instead of actual volume so LuxCore will still start to render
            self.properties.Set(pyluxcore.Property(prefix + '.type', ['clear']))