# Copyright (C) <2021>  <Reston Stanton>

# ##### BEGIN GPL LICENSE BLOCK #####
#
# 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 3 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
# MERCHANTIBILITY 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 LICENSE BLOCK #####


import bpy
import os

from .. import preferences
from ..Shared import ops, material, modifiers

"""
    ██████                                  █████     ███
   ███░░███                                ░░███     ░░░
  ░███ ░░░  █████ ████ ████████    ██████  ███████   ████   ██████  ████████    █████
 ███████   ░░███ ░███ ░░███░░███  ███░░███░░░███░   ░░███  ███░░███░░███░░███  ███░░
░░░███░     ░███ ░███  ░███ ░███ ░███ ░░░   ░███     ░███ ░███ ░███ ░███ ░███ ░░█████
  ░███      ░███ ░███  ░███ ░███ ░███  ███  ░███ ███ ░███ ░███ ░███ ░███ ░███  ░░░░███
  █████     ░░████████ ████ █████░░██████   ░░█████  █████░░██████  ████ █████ ██████
 ░░░░░       ░░░░░░░░ ░░░░ ░░░░░  ░░░░░░     ░░░░░  ░░░░░  ░░░░░░  ░░░░ ░░░░░ ░░░░░░

"""


def set_domain(context, domain):
    pref = preferences.get_preferences()

    domain.modifiers["Fluid"].fluid_type = 'DOMAIN'

    modifier_settings = domain.modifiers["Fluid"].domain_settings

    modifier_settings.domain_type = 'GAS'
    modifier_settings.cache_frame_end = 250
    modifier_settings.use_adaptive_domain = True
    modifier_settings.use_noise = True
    modifier_settings.use_dissolve_smoke = True
    modifier_settings.cache_resumable = True

    modifier_settings.resolution_max = pref.gas_resolution
    modifier_settings.time_scale = pref.gas_sim_speed

    material.add_material(domain, "MantaPro Gas")

    ops.set_domain_index(context, domain)

    if bpy.data.filepath:
        domain.MantaPro.moved_cache = True


def set_flow(context, obj):
    ops.set_flow_index(context, obj)


"""
  █████████   ███                      ████                                                     █████     ███
 ███░░░░░███ ░░░                      ░░███                                                    ░░███     ░░░
░███    ░░░  ████  ████████    ███████ ░███   ██████      ██████  ████████   ██████   ██████   ███████   ████   ██████  ████████       ██████  ████████   █████
░░█████████ ░░███ ░░███░░███  ███░░███ ░███  ███░░███    ███░░███░░███░░███ ███░░███ ░░░░░███ ░░░███░   ░░███  ███░░███░░███░░███     ███░░███░░███░░███ ███░░
 ░░░░░░░░███ ░███  ░███ ░███ ░███ ░███ ░███ ░███████    ░███ ░░░  ░███ ░░░ ░███████   ███████   ░███     ░███ ░███ ░███ ░███ ░███    ░███ ░███ ░███ ░███░░█████
 ███    ░███ ░███  ░███ ░███ ░███ ░███ ░███ ░███░░░     ░███  ███ ░███     ░███░░░   ███░░███   ░███ ███ ░███ ░███ ░███ ░███ ░███    ░███ ░███ ░███ ░███ ░░░░███
░░█████████  █████ ████ █████░░███████ █████░░██████    ░░██████  █████    ░░██████ ░░████████  ░░█████  █████░░██████  ████ █████   ░░██████  ░███████  ██████
 ░░░░░░░░░  ░░░░░ ░░░░ ░░░░░  ░░░░░███░░░░░  ░░░░░░      ░░░░░░  ░░░░░      ░░░░░░   ░░░░░░░░    ░░░░░  ░░░░░  ░░░░░░  ░░░░ ░░░░░     ░░░░░░   ░███░░░  ░░░░░░
                              ███ ░███                                                                                                         ░███
                             ░░██████                                                                                                          █████
                              ░░░░░░                                                                                                          ░░░░░
"""


class MantaProDomain(bpy.types.Operator):
    bl_idname = "mantapro_gas.make_domain"
    bl_label = "make selected domain"
    bl_description = "make selected object an domain"

    bl_options = {'REGISTER', 'UNDO'}

    @ classmethod
    def poll(cls, context):
        return ops.add_poll(context)

    def execute(self, context):
        scene_set = context.scene.MantaPro
        # get current area
        area = context.area.ui_type
        context.area.ui_type = "VIEW_3D"
        bpy.ops.object.modifier_add(type='FLUID')

        set_domain(context, context.active_object)

        context.area.ui_type = area

        if preferences.get_preferences().auto_ops:
            context.scene.MantaPro.auto_ops = True
        return {'FINISHED'}


class MantaProAddDomain(bpy.types.Operator):
    bl_idname = "mantapro_gas.add_domain"
    bl_label = "add domain object"
    bl_description = "add domain object to scene"

    bl_options = {'REGISTER', 'UNDO'}

    @ classmethod
    def poll(cls, context):
        return True

    def execute(self, context):
        # add domain object
        cursor = context.scene.cursor.location
        bpy.ops.mesh.primitive_cube_add(
            size=2, enter_editmode=False, location=cursor)
        domain = bpy.context.active_object
        domain.name = "domain"
        bpy.ops.object.editmode_toggle()
        bpy.ops.transform.translate(value=(0, 0, 1))
        bpy.ops.object.editmode_toggle()

        domain.scale = (5, 5, 5)
        bpy.ops.object.modifier_add(type='FLUID')
        bpy.ops.object.shade_smooth()
        set_domain(context, domain)

        if preferences.get_preferences().auto_ops:
            context.scene.MantaPro.auto_ops = True
        return {'FINISHED'}


class MantaProFlow(bpy.types.Operator):
    bl_idname = "mantapro_gas.make_flow"
    bl_label = "make selected flow"
    bl_description = "make selected object an flow"

    bl_options = {'REGISTER', 'UNDO'}

    @ classmethod
    def poll(cls, context):
        return ops.add_poll(context)

    def execute(self, context):
        # get current area
        area = context.area.ui_type
        context.area.ui_type = "VIEW_3D"
        defaults = preferences.get_preferences()

        obj = context.active_object

        set_flow(context, obj)

        bpy.ops.object.modifier_add(type='FLUID')
        obj.modifiers["Fluid"].fluid_type = 'FLOW'
        modifier_settings = obj.modifiers["Fluid"].flow_settings
        modifier_settings.flow_type = defaults.gas_flow_type
        modifier_settings.flow_behavior = "INFLOW"
        obj.MantaPro.flow_type = modifier_settings.flow_type
        ops.move_to_collection(obj, "FLOW", context)

        context.area.ui_type = area

        if preferences.get_preferences().auto_ops:
            context.scene.MantaPro.auto_ops = True
        return {'FINISHED'}


"""
 ██████████                                       ███
░░███░░░░███                                     ░░░
 ░███   ░░███  ██████  █████████████    ██████   ████  ████████       ██████  ████████   █████
 ░███    ░███ ███░░███░░███░░███░░███  ░░░░░███ ░░███ ░░███░░███     ███░░███░░███░░███ ███░░
 ░███    ░███░███ ░███ ░███ ░███ ░███   ███████  ░███  ░███ ░███    ░███ ░███ ░███ ░███░░█████
 ░███    ███ ░███ ░███ ░███ ░███ ░███  ███░░███  ░███  ░███ ░███    ░███ ░███ ░███ ░███ ░░░░███
 ██████████  ░░██████  █████░███ █████░░████████ █████ ████ █████   ░░██████  ░███████  ██████
░░░░░░░░░░    ░░░░░░  ░░░░░ ░░░ ░░░░░  ░░░░░░░░ ░░░░░ ░░░░ ░░░░░     ░░░░░░   ░███░░░  ░░░░░░
                                                                              ░███
                                                                              █████
                                                                             ░░░░░
"""


class MantaProMultiColor(bpy.types.Operator):
    bl_idname = "mantapro_gas.multi_color"
    bl_label = "multi_color"
    bl_description = "make smoke multi color"

    remove: bpy.props.BoolProperty(name="remove")

    @ classmethod
    def poll(cls, context):
        domain = context.scene.MantaPro.active_domain
        if domain:
            return True
        else:
            return False

    def execute(self, context):
        domain = context.scene.MantaPro.active_domain
        name = material.get_name(domain)
        tree = domain.material_slots[name].material.node_tree

        link = tree.links.new(tree.nodes["Principled Volume"].inputs["Color"],
                              tree.nodes["Multicolor"].outputs["Color"],)

        if self.remove:
            tree.links.remove(link)

        return {'FINISHED'}


class MantaProFlamePlus(bpy.types.Operator):
    bl_idname = "mantapro_gas.flame_plus"
    bl_label = "flame+"
    bl_description = "make fire flame+"

    remove: bpy.props.BoolProperty(name="remove")

    @ classmethod
    def poll(cls, context):
        domain = context.scene.MantaPro.active_domain
        if domain:
            return True
        else:
            return False

    def execute(self, context):
        domain = context.scene.MantaPro.active_domain
        name = material.get_name(domain)
        tree = domain.material_slots[name].material.node_tree

        link1 = tree.links.new(tree.nodes["Principled Volume"].inputs["Density"],
                               tree.nodes["Flame+"].outputs["Density"],)

        link2 = tree.links.new(tree.nodes["Principled Volume"].inputs["Temperature"],
                               tree.nodes["Flame+"].outputs["Temperature"],)

        link3 = tree.links.new(tree.nodes["Principled Volume"].inputs["Blackbody Intensity"],
                               tree.nodes["Flame+"].outputs["Fire"],)

        if self.remove:
            tree.links.remove(link1)
            tree.links.remove(link2)
            tree.links.remove(link3)

        return {'FINISHED'}


"""
 ███████████ ████
░░███░░░░░░█░░███
 ░███   █ ░  ░███   ██████  █████ ███ █████     ██████  ████████   █████
 ░███████    ░███  ███░░███░░███ ░███░░███     ███░░███░░███░░███ ███░░
 ░███░░░█    ░███ ░███ ░███ ░███ ░███ ░███    ░███ ░███ ░███ ░███░░█████
 ░███  ░     ░███ ░███ ░███ ░░███████████     ░███ ░███ ░███ ░███ ░░░░███
 █████       █████░░██████   ░░████░████      ░░██████  ░███████  ██████
░░░░░       ░░░░░  ░░░░░░     ░░░░ ░░░░        ░░░░░░   ░███░░░  ░░░░░░
                                                        ░███
                                                        █████
                                                       ░░░░░
"""


class MantaProFlowSync(bpy.types.Operator):
    bl_idname = "mantapro_gas.flow_sync"
    bl_label = "sync"
    bl_description = "sync flow type"

    @ classmethod
    def poll(cls, context):
        if modifiers.check_type_gas(context.scene.MantaPro.active_flow, "FLOW"):
            modifier_settings = modifiers.find_modifier(
                context.scene.MantaPro.active_flow).flow_settings
            if modifier_settings.noise_texture:
                return False
            else:
                return True
        else:
            return False

    def execute(self, context):
        modifier_settings = modifiers.find_modifier(
            context.scene.MantaPro.active_flow).flow_settings
        flow_type = modifier_settings.flow_type
        context.scene.MantaPro.active_flow.MantaPro.flow_type = flow_type
        return {'FINISHED'}


class MantaProTextureSetup(bpy.types.Operator):
    bl_idname = "mantapro_gas.texture_setup"
    bl_label = "Texture Setup"
    bl_description = "setup a texture automatically"

    @ classmethod
    def poll(cls, context):
        if modifiers.check_type_gas(context.scene.MantaPro.active_flow, "FLOW"):
            modifier_settings = modifiers.find_modifier(
                context.scene.MantaPro.active_flow).flow_settings
            if modifier_settings.noise_texture:
                return False
            else:
                return True
        else:
            return False

    def execute(self, context):
        modifier_settings = modifiers.find_modifier(
            context.scene.MantaPro.active_flow).flow_settings
        texture = bpy.data.textures.new("MantaPro", "CLOUDS")
        texture.contrast = 2
        modifier_settings.noise_texture = texture
        modifier_settings.texture_size = 0.25
        return {'FINISHED'}


class MantaProPaintStart(bpy.types.Operator):
    bl_idname = "mantapro_gas.paint_start"
    bl_label = "Start Painting"
    bl_description = "paint flow influence on selected object \n NOTE: works best on higher poly objects"

    @ classmethod
    def poll(cls, context):
        if modifiers.check_type_gas(context.scene.MantaPro.active_flow, "FLOW"):
            modifier_settings = modifiers.find_modifier(
                context.scene.MantaPro.active_flow).flow_settings
            return True
        else:
            return False

    def execute(self, context):
        obj = context.scene.MantaPro.active_flow
        modifier_settings = modifiers.find_modifier(
            obj).flow_settings

        if not "MantaPro" in obj.vertex_groups:
            obj.vertex_groups.new(name="MantaPro")

        modifier_settings.density_vertex_group = "MantaPro"

        context.view_layer.objects.active = obj
        obj.select_set(True)

        bpy.ops.paint.weight_paint_toggle()
        obj.vertex_groups.active = obj.vertex_groups[
            "MantaPro"]
        return {'FINISHED'}


class MantaProPaintEnd(bpy.types.Operator):
    bl_idname = "mantapro_gas.paint_end"
    bl_label = "Stop Painting"
    bl_description = "exit painting"

    @ classmethod
    def poll(cls, context):
        if modifiers.check_type_gas(context.scene.MantaPro.active_flow, "FLOW"):
            modifier_settings = modifiers.find_modifier(
                context.scene.MantaPro.active_flow).flow_settings
            return True
        else:
            return False

    def execute(self, context):

        bpy.ops.paint.weight_paint_toggle()
        return {'FINISHED'}


class MantaProFlowPaint(bpy.types.Operator):
    bl_idname = "mantapro_gas.make_paint"
    bl_label = "Start Painting Selected object (GAS ONLY)"
    bl_description = "make selected gas flow object and start painting it"

    bl_options = {'REGISTER', 'UNDO'}

    @ classmethod
    def poll(cls, context):
        return ops.add_poll(context)

    def execute(self, context):
        bpy.ops.mantapro_gas.make_flow()
        bpy.ops.mantapro_gas.paint_start()
        return {'FINISHED'}


class MantaProGasRestoreGravity(bpy.types.Operator):
    bl_idname = "mantapro_gas.restore_gravity"
    bl_label = "Restore Gravity"
    bl_description = "Restore gravity to default values"

    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        if context.scene.use_gravity:
            context.scene.gravity = (0, 0, -9.81)
        else:
            modifier_settings = modifiers.get_modifier_domain(
                domain=context.scene.MantaPro.active_domain)
            modifier_settings.gravity = (0, 0, -9.81)
        return {'FINISHED'}


classes = (
    MantaProDomain,
    MantaProFlow,
    MantaProAddDomain,

    MantaProTextureSetup,

    MantaProFlowSync,

    MantaProPaintStart,
    MantaProPaintEnd,
    MantaProFlowPaint,

    MantaProGasRestoreGravity,

    MantaProMultiColor,
    MantaProFlamePlus,)


def register():
    for i in classes:
        bpy.utils.register_class(i)


def unregister():
    for i in classes:
        bpy.utils.unregister_class(i)
