# Copyright 2015 Théo Friberg under GNU GPL 3

if "bpy" in locals():
    import importlib
    importlib.reload(JSONOps)
else:
    from . import JSONOps

import bpy
import os
import glob

class AutomatOperatorFromTexture(bpy.types.Operator):
    """This operator generates automatic materials from textures in Cycles"""

    # Metadata of the operator

    bl_idname = "com.new_automat"
    bl_label = "Automatic Material from Image"
    bl_options = {"UNDO"}

    # Variables used for storing the filepath given by blender's file manager

    filepath: bpy.props.StringProperty(subtype="FILE_PATH")
    filename: bpy.props.StringProperty()
    directory: bpy.props.StringProperty(subtype="FILE_PATH")

    make_seamless: bpy.props.BoolProperty(
        name="Make Seamless",
        description="Make tileable (removes visible borders of the image)",
    )

    def execute(self, context):

        """This is the main runnable method of the operator.

This creates all the node setup."""

        # Create the material

        mat = bpy.data.materials.new(self.filename)

        mat.use_nodes = True
        nodes = mat.node_tree.nodes

        # Empty whatever nodes we allready had.

        for node in nodes.keys():
            nodes.remove(nodes[node])

        nodes_dict = {}

        # Create the main part of the material

        nodes_dict = JSONOps.inflateFile(mat, os.path.dirname(
                                      os.path.realpath(__file__))+os.sep+
                                      "automatic_material.json")



        # We load the images

        image_data = bpy.data.images.load(self.filepath)
        nodes_dict["Color Image"].image = image_data

        # We check if the texture must be made seamless

        if self.make_seamless:
            seamless_vector = JSONOps.inflateFile(mat, os.path.dirname(os.path.realpath(__file__))+os.sep+"seamless_vector.json", -3000, 0)
            links = mat.node_tree.links
            links.new(seamless_vector["Pick Vector"].outputs["Color"], nodes_dict["Color Image"].inputs["Vector"])

        # Below we check potential maps

        modified_fname = self.filename.split(".")

        # Check if we are dealing with maps generated with CrazyBump.
        # If so is the case, the color map is by default suffixed with _COLOR

        known_scheme = False

        if modified_fname[0][-6:] == "_COLOR":

            # We are dealing with CrazyBump and we remove the suffix

            modified_fname[0] = modified_fname[0][:-6]
            known_scheme = True

        other_files = []
        folder = os.path.split(self.filepath)[0]+os.path.sep+"*"
        pattern = folder + ".".join(modified_fname[:-1])+"*."+modified_fname[-1]
        other_files = glob.glob(pattern)

        # We check if we can find a Specularity Map

        specmap = ""

        for file in other_files:
            if "spec" in os.path.split(file)[-1].lower():
                specmap = file
                break

        if len(specmap) > 0:

            spec_map = nodes.new("ShaderNodeTexImage")
            spec_map.location = [nodes_dict["Adjust reflectivity"].location[0],
                                 nodes_dict["Adjust reflectivity"].location[1]+50]
            spec_map.label = "Specularity Map"
            nodes.remove(nodes_dict["Adjust reflectivity"])
            spec_map.image = bpy.data.images.load(specmap)
            links = mat.node_tree.links

            links.new(spec_map.outputs["Color"],
                      nodes_dict["Mix Shaders"].inputs[0])
            if self.make_seamless:
                links.new(seamless_vector["Pick Vector"].outputs["Color"], spec_map.inputs["Vector"])

        # We check if we can find a Normal Map

        normalmap = ""

        for file in other_files:
            if "normal" in os.path.split(file)[-1].lower() or ".".join(os.path.split(file)[1].split(".") [:-1])[-4:] == "_NRM":
                normalmap = file
                break

        if len(normalmap) > 0 and ((not "normal" in self.filename.lower()) or known_scheme):

            normal_map = nodes.new("ShaderNodeTexImage")
            normal_map.location = [nodes_dict["Color Image"].location[0],
                                   nodes_dict["Color Image"].location[1]-240]
            normal_map.label = "Normal Map"
            normal_map.image = bpy.data.images.load(normalmap)
            links = mat.node_tree.links

            normal = nodes.new("ShaderNodeNormalMap")
            normal.location = [nodes_dict["Convert to Bump Map"].location[0],
                               nodes_dict["Convert to Bump Map"].location[1]]
            nodes.remove(nodes_dict["Convert to Bump Map"])
            links.new(normal_map.outputs["Color"],
                      normal.inputs[1])
            links.new(normal.outputs["Normal"],
                      nodes_dict["Diffuse Component"].inputs[2])
            links.new(normal.outputs["Normal"],
                      nodes_dict["Glossy Component"].inputs[2])
            if self.make_seamless:
                links.new(seamless_vector["Pick Vector"].outputs["Color"], normal_map.inputs["Vector"])

        # We check if we can find a Bump Map

        bumpmap = ""

        for file in other_files:
            if "bump" in os.path.split(file.lower())[-1]:
                bumpmap = file
                break

        if len(bumpmap) > 0 and not "bump" in self.filename.lower() and not len(normalmap) > 0:

            bump_map = nodes.new("ShaderNodeTexImage")
            bump_map.location = [nodes_dict["Color Image"].location[0],
                                 nodes_dict["Color Image"].location[1]-240]
            bump_map.label = "Bump Map"
            bump_map.image = bpy.data.images.load(bumpmap)
            links = mat.node_tree.links
            links.new(bump_map.outputs["Color"], nodes_dict["Convert to Bump Map"].inputs[2])
            if self.make_seamless:
                links.new(seamless_vector["Pick Vector"].outputs["Color"], bump_map.inputs["Vector"])

        # Try to add the material to the selected object
        try:
            bpy.context.object.data.materials.append(mat)
        except AttributeError:

            # If there is no object with materials selected,
            # don't add the material to anythinng.

            pass

        # Tell that all went well

        return {"FINISHED"}

    def invoke(self, context, event):

        """This method opens the file browser. After that, the
execute(...) method gets ran, creating the node setup.
It also checks that the render engine is Cycles.  """

        if bpy.context.scene.render.engine == 'CYCLES':
            self.filename = ""
            context.window_manager.fileselect_add(self)
            return {"RUNNING_MODAL"}
        else:
            self.report({'ERROR'}, "Can't generate Cycles material with Blender"
            "internal as active renderer.")
            return {"FINISHED"}