#!/usr/bin/env python
#
############################################################################
#
# MODULE:        r.shade
# AUTHOR(S):     Hamish Bowman
#                Vaclav Petras <wenzeslaus gmail com>
#                Inspired by d.shade (formerly d.shadedmap)
# PURPOSE:       Uses r.his to drape a color raster over a shaded relief map
# COPYRIGHT:     (C) 2014 by Hamish Bowman, and the GRASS Development Team
#
#                This program is free software under the GNU General Public
#                License (>=v2). Read the file COPYING that comes with GRASS
#                for details.
#
#############################################################################

#%module
#% description: Drapes a color raster over an shaded relief or aspect map.
#% keyword: raster
#% keyword: elevation
#% keyword: relief
#% keyword: hillshade
#% keyword: visualization
#%end
#%option G_OPT_R_INPUT
#% key: shade
#% description: Name of shaded relief or aspect raster map
#%end
#%option G_OPT_R_INPUT
#% key: color
#% label: Name of raster to drape over relief raster map
#% description: Typically, this raster is elevation or other colorful raster
#%end
#%option G_OPT_R_OUTPUT
#% description: Name of shaded raster map
#%end
#%option
#% key: brighten
#% type: integer
#% description: Percent to brighten
#% options: -99-99
#% answer: 0
#%end
#%option
#% key: bgcolor
#% type: string
#% key_desc: name
#% label: Color to use instead of NULL values
#% description: Either a standard color name, R:G:B triplet, or "none"
#% gisprompt: old,color_none,color
#%end
#%flag
#% key: c
#% description: Use colors from color tables for NULL values
#%end
#%rules
#% exclusive: bgcolor, -c
#%end

# TODO: bgcolor is not using standard option because it has default white
# using `answer:` will cause `default:` which is not the same as no default


import os
from grass.script import core as gcore
from grass.script import raster as grast
from grass.exceptions import CalledModuleError


def remove(maps):
    """Remove raster maps"""
    gcore.run_command('g.remove', flags='f', quiet=True,
                      type='rast', name=maps)


def main():
    options, flags = gcore.parser()

    drape_map = options['color']
    relief_map = options['shade']
    brighten = int(options['brighten'])
    output_map = options['output']
    bgcolor = options['bgcolor']

    rhis_extra_args = {}
    if bgcolor:
        rhis_extra_args['bgcolor'] = bgcolor
    if flags['c']:
        rhis_extra_args['flags'] = 'c'

    to_remove = []
    try:
        unique_name = 'tmp__rshade_%d' % os.getpid()
        tmp_base = '%s_drape' % unique_name
        tmp_r = tmp_base + '.r'
        tmp_g = tmp_base + '.g'
        tmp_b = tmp_base + '.b'

        if brighten:
            # steps taken from r.his manual page
            # how much they are similar with d.shade/d.his is unknown
            # perhaps even without brightness, there can be some differences
            # comparing to d.shade
            relief_map_tmp = '%s_relief' % unique_name
            # convert [-99, -99] to [0.01, 1.99]
            brighten = 1 + brighten / 100.
            grast.mapcalc('{n} = {c} * #{o}'.format(
                n=relief_map_tmp, o=relief_map, c=brighten))
            gcore.run_command('r.colors', map=relief_map_tmp, color='grey255')
            relief_map = relief_map_tmp
            to_remove.append(relief_map_tmp)
        gcore.run_command('r.his', hue=drape_map, intensity=relief_map,
                          red=tmp_r, green=tmp_g, blue=tmp_b,
                          **rhis_extra_args)
        to_remove.extend([tmp_r, tmp_g, tmp_b])
        gcore.run_command('r.composite', red=tmp_r, green=tmp_g,
                          blue=tmp_b, output=output_map)
        remove(to_remove)  # who knows if finally is called when exit
    except CalledModuleError as error:
        remove(to_remove)
        # TODO: implement module name to CalledModuleError
        gcore.fatal(_("Module %s failed. Check the above error messages.") %
                    error.cmd)


if __name__ == "__main__":
    main()
