"""
Blockdiag Tag
---------
This tag implements a liquid style tag for blockdiag [1].  You can use different
diagram types like blockdiag, seqdiag, packetdiag etc. [1]


[1] http://blockdiag.com/en/blockdiag/

Syntax
------
{% blockdiag
    <diagramm type> {
        <CODE>
    }
%}

Examples
--------
{% blockdiag
    blockdiag {
        A -> B -> C;
        B -> D;
    }
%}


{% blockdiag
    actdiag {
        A -> B -> C -> D -> E;

        lane {
        A; C; E;
        }
        lane {
        B; D;
        }
    }
%}


{% blockdiag
    packetdiag {
        0-7: Source Port
        8-15: Destination Port
        16-31: Sequence Number
        32-47: Acknowledgment Number
    }
%}

...


Output
------
<span class="blockdiag" style="align: center;"><img src="data:image/png;base64,_BASE64_IMAGE DATA_/></span>

"""

import base64
import os
import re

from .mdx_liquid_tags import LiquidTags

SYNTAX = "{% blockdiag [diagram type] [code] %}"
DOT_BLOCK_RE = re.compile(r"^\s*(?P<diagram>\w+).*$", re.MULTILINE | re.DOTALL)

_draw_mode = "PNG"
_publish_mode = "PNG"


def get_diag(code, command):
    """Generate diagramm and return data"""
    import shutil
    import tempfile

    code = code + "\n"

    try:
        tmpdir = tempfile.mkdtemp()
        fd, diag_name = tempfile.mkstemp(dir=tmpdir)

        f = os.fdopen(fd, "w")
        f.write(code)
        f.close()

        format = _draw_mode.lower()
        draw_name = diag_name + "." + format

        argv = [diag_name, "-T", format, "-o", draw_name]

        if _draw_mode == "SVG":
            argv += ["--ignore-pil"]

        # Run command
        command.main(argv)

        # Read image data from file
        file_name = diag_name + "." + _publish_mode.lower()

        with open(file_name, "rb") as f:
            data = f.read()
            f.close()

    finally:
        for file in os.listdir(tmpdir):
            os.unlink(tmpdir + "/" + file)

        # os.rmdir will fail -> use shutil
        shutil.rmtree(tmpdir)

    return data


def diag(code, command):
    if command == "blockdiag":  # blockdiag
        import blockdiag.command

        return get_diag(code, blockdiag.command)

    elif command == "diagram":  # diagram
        import blockdiag.command

        return get_diag(code, blockdiag.command)

    elif command == "seqdiag":  # seqdiag
        import seqdiag.command

        return get_diag(code, seqdiag.command)

    elif command == "actdiag":  # actdiag
        import actdiag.command

        return get_diag(code, actdiag.command)

    elif command == "nwdiag":  # nwdiag
        import nwdiag.command

        return get_diag(code, nwdiag.command)

    elif command == "packetdiag":  # packetdiag
        import packetdiag.command

        return get_diag(code, packetdiag.command)

    elif command == "rackdiag":  # racketdiag
        import rackdiag.command

        return get_diag(code, rackdiag.command)

    else:  # not found
        print("No such command %s" % command)
        return None


@LiquidTags.register("blockdiag")
def blockdiag_parser(preprocessor, tag, markup):
    """Blockdiag parser"""
    m = DOT_BLOCK_RE.search(markup)
    if m:
        # Get diagram type and code
        diagram = m.group("diagram").strip()
        code = markup

        # Run command
        output = diag(code, diagram)

        if output:
            base64_data = base64.b64encode(output).decode("UTF-8")
            # Return Base64 encoded image
            return (
                '<span class="blockdiag" style="align: center;">'
                '<img src="data:image/png;base64,%s"></span>'
            ) % base64_data
    else:
        raise ValueError(
            "Error processing input. " "Expected syntax: {}".format(SYNTAX)
        )


# This import allows diag tag to be a Pelican plugin
from .liquid_tags import register  # noqa
