"""
This module provides methods for compiling the plugin
"""

__author__ = "Bernhard Esperester <bernhard@esperester.de>"


import os

from imp import load_source

import bootstrap
from bootstrap.reducers.res import reduce_resource
from bootstrap.reducers.h import reduce_header
from bootstrap.reducers.str import reduce_strings

from bootstrap.render.res import render_resource
from bootstrap.render.h import render_header
from bootstrap.render.str import render_strings

from bootstrap.utilities.path import assert_directories

COMMENT_C = "// "
"""
Comment indicator for C-Type files
"""

COMMENT_PYTHON = "# "
"""
Comment indicator for python files
"""

PREFIX = "generated by bootstrap for c4d version {}".format(
    bootstrap.__version__
)
"""
Prefix to prepend to compiled files
"""


def write_resource(description, destination_directory, filename):
    """
    This method compiles the description to a resource file.
    :param description: bootstrap.Description
    :param destination_directory: string
    :param filename: string
    :return:
    """
    destination_file = os.path.join(
        destination_directory, "res/description",
        "{}.res".format(filename)
    )

    contents = render_resource(reduce_resource(description))

    contents = "\n".join([COMMENT_C + PREFIX, contents])

    assert_directories(destination_file, True)

    with open(destination_file, "w") as f:
        f.write(contents)

    print("done writing {}".format(destination_file))


def write_header(description, destination_directory, filename):
    """
    This method compiles the description to a header file.
    :param description: bootstrap.Description
    :param destination_directory: string
    :param filename: string
    :return:
    """
    destination_file = os.path.join(
        destination_directory, "res/description",
        "{}.h".format(filename)
    )

    contents = render_header(reduce_header(description))

    contents = "\n".join([COMMENT_C + PREFIX, contents])

    assert_directories(destination_file, True)

    with open(destination_file, "w") as f:
        f.write(contents)

    print("done writing {}".format(destination_file))


def write_strings(description, destination_directory, filename):
    """
    This method compiles the description to string files.
    :param description: bootstrap.Description
    :param destination_directory: string
    :param filename: string
    :return:
    """
    strings_rendered = render_strings(reduce_strings(description))

    for key, contents in strings_rendered.items():
        destination_file = os.path.join(
            destination_directory, "res", key, "description",
            "{}.str".format(filename)
        )

        contents = "\n".join([COMMENT_C + PREFIX, contents])

        assert_directories(destination_file, True)

        with open(destination_file, "w") as f:
            f.write(contents)

        print("done writing {}".format(destination_file))


def compile_plugin(plugin_file, destination_directory, filename):
    """
    This method compiles the python plugin to a cinema 4d pyp file.
    :param plugin_file: string
    :param destination_directory: string
    :param filename: string
    :return:
    """
    plugin_filename, plugin_fileextension = os.path.splitext(
        os.path.basename(plugin_file)
    )

    with open(plugin_file, "r") as input_file:
        lines = input_file.read().split("\n")

        lines_computed = []

        ignore_lines = False
        id_section = False

        module = load_source(plugin_filename, plugin_file)

        for line in lines:
            # id section
            if line.startswith("#----begin_id_section----"):
                id_section = True

                lines_computed.append(COMMENT_PYTHON + PREFIX)

                continue

            if line.startswith("#----end_id_section----"):
                id_section = False

                continue

            if id_section:
                if line.startswith("#"):
                    continue

                if not line:
                    continue

                variables = [x.strip() for x in line.split("=")]

                if variables:
                    variableName = variables[0]

                    lines_computed.append(
                        "{} = {}".format(
                            variableName,
                            getattr(module, variableName)
                        )
                    )

                continue

            # skip bootstrap lines
            if line.startswith("#----begin"):
                ignore_lines = True

                continue

            if line.startswith("#----end"):
                ignore_lines = False

                continue

            if not ignore_lines:
                lines_computed.append(line)

        compiled_plugin_file = os.path.join(
            destination_directory, "{}.pyp".format(filename)
        )

        assert_directories(compiled_plugin_file, True)

        with open(compiled_plugin_file, "w") as output_file:
            output_file.write("\n".join(lines_computed))

        print("done writing {}".format(compiled_plugin_file))


def build(description, plugin_file, destination_directory, filename):
    """
    This method compiles all necessary plugin files.
    :param description: bootstrap.Description
    :param plugin_file: string
    :param destination_directory: string
    :param filename: string
    :return:
    """
    write_header(description, destination_directory, filename)

    write_resource(description, destination_directory, filename)

    write_strings(description, destination_directory, filename)

    compile_plugin(plugin_file, destination_directory, filename)

    return True
