#!/usr/bin/env python3
import os
import sys
import tempfile

from grass.script import core as grass
from grass.script import task as gtask
from grass.exceptions import CalledModuleError


# read environment variables from file
def read_env_file(env_file):
    width = height = legfile = None
    fd = open(env_file, "r")
    if fd is None:
        grass.fatal("Unable to open file '{0}'".format(env_file))
    lines = fd.readlines()
    for line in lines:
        if line.startswith("#"):
            continue
        k, v = line.rstrip("\n").split("#", 1)[0].strip().split("=", 1)
        os.environ[k] = v
        if width is None and k == "GRASS_RENDER_WIDTH":
            width = int(v)
        if height is None and k == "GRASS_RENDER_HEIGHT":
            height = int(v)
        if legfile is None and k == "GRASS_LEGEND_FILE":
            legfile = v
    fd.close()

    if width is None or height is None:
        grass.fatal("Unknown monitor size")

    return width, height, legfile


# run display command
def render(cmd, mapfile):
    env = os.environ.copy()

    if mapfile:
        env["GRASS_RENDER_FILE"] = mapfile
    try:
        grass.run_command(cmd[0], env=env, **cmd[1])
    except CalledModuleError as e:
        grass.debug("Unable to render: {0}".format(e), 1)


# update cmd file
def update_cmd_file(cmd_file, cmd, mapfile):
    if cmd[0] in (
        "d.colorlist",
        "d.font",
        "d.fontlist",
        "d.frame",
        "d.info",
        "d.mon",
        "d.out.file",
        "d.redraw",
        "d.to.rast",
        "d.what.rast",
        "d.what.vect",
        "d.where",
    ):
        return

    mode = "w" if cmd[0] == "d.erase" else "a"
    # update cmd file
    fd = open(cmd_file, mode)
    if fd is None:
        grass.fatal("Unable to open file '{0}'".format(cmd_file))
    if mode == "a":
        frame = os.getenv("GRASS_RENDER_FRAME", None)
        if frame:
            fd.write("# GRASS_RENDER_FRAME={0}\n".format(frame))
        if mapfile:
            fd.write("# GRASS_RENDER_FILE={0}\n".format(mapfile))
        fd.write(" ".join(gtask.cmdtuple_to_list(cmd)))
        fd.write("\n")
    else:
        fd.write("")
    fd.close()


# adjust region
def adjust_region(width, height):
    region = grass.region()

    mapwidth = abs(region["e"] - region["w"])
    mapheight = abs(region["n"] - region["s"])

    region["nsres"] = mapheight / height
    region["ewres"] = mapwidth / width
    region["rows"] = int(round(mapheight / region["nsres"]))
    region["cols"] = int(round(mapwidth / region["ewres"]))
    region["cells"] = region["rows"] * region["cols"]

    kwdata = [
        ("proj", "projection"),
        ("zone", "zone"),
        ("north", "n"),
        ("south", "s"),
        ("east", "e"),
        ("west", "w"),
        ("cols", "cols"),
        ("rows", "rows"),
        ("e-w resol", "ewres"),
        ("n-s resol", "nsres"),
    ]

    grass_region = ""
    for wkey, rkey in kwdata:
        grass_region += "%s: %s;" % (wkey, region[rkey])

    os.environ["GRASS_REGION"] = grass_region


# read any input from stdin and create a temporary file
def read_stdin(cmd):
    opt = None

    if (
        cmd[0] == "d.text"
        and "text" not in cmd[1]
        and ("input" not in cmd[1] or cmd[1]["input"] == "-")
    ):
        if sys.stdin.isatty():
            sys.stderr.write(
                "\nPlease enter text instructions."
                " Enter EOF (ctrl-d) on last line to quit.\n"
            )
        opt = "input"

    if opt:
        tmpfile = tempfile.NamedTemporaryFile(dir=path).name + ".txt"
        fd = open(tmpfile, "w")
        while 1:
            line = sys.stdin.readline()
            if not line:
                break
            fd.write(line)
        fd.close()
        cmd[1][opt] = tmpfile


if __name__ == "__main__":
    cmd = gtask.cmdstring_to_tuple(sys.argv[1])
    if not cmd[0] or cmd[0] == "d.mon":
        sys.exit(0)
    path = os.path.dirname(os.path.abspath(__file__))
    mon = os.path.split(path)[-1]

    width, height, legfile = read_env_file(os.path.join(path, "env"))
    if mon.startswith("wx"):
        mapfile = tempfile.NamedTemporaryFile(dir=path).name
        if cmd[0] in ("d.barscale", "d.legend", "d.northarrow", "d.legend.vect"):
            mapfile += ".png"
        else:
            mapfile += ".ppm"
    else:
        mapfile = None
        adjust_region(width, height)

    read_stdin(cmd)

    render(cmd, mapfile)
    update_cmd_file(os.path.join(path, "cmd"), cmd, mapfile)
    if cmd[0] == "d.erase" and os.path.exists(legfile):
        os.remove(legfile)

    sys.exit(0)
