#!/opt/local/bin/python3.11

############################################################################
#
# MODULE:       i.in.spot
#
# AUTHOR(S):    Markus Neteler
#               Converted to Python by Glynn Clements
#
# PURPOSE:      Import SPOT VEGETATION data into a GRASS raster map
#               SPOT Vegetation (1km, global) data:
#               http://free.vgt.vito.be/
#
# COPYRIGHT:    (c) 2004-2011 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.
#
#############################################################################
#
# REQUIREMENTS:
#      -  gdal: http://www.gdal.org
#
# Notes:
# * According to the faq (http://www.vgt.vito.be/faq/faq.html), SPOT vegetation
#   coordinates refer to the center of a pixel.
# * GDAL coordinates refer to the corner of a pixel
#   -> correction of 0001/0001_LOG.TXT coordinates by 0.5 pixel
#############################################################################

#%module
#% description: Imports SPOT VGT NDVI data into a raster map.
#% keyword: imagery
#% keyword: import
#% keyword: NDVI
#% keyword: SPOT
#%end
#%flag
#% key: a
#% description: Also import quality map (SM status map layer) and filter NDVI map
#%end
#%option G_OPT_F_INPUT
#% description: Name of input SPOT VGT NDVI HDF file
#%end
#% option G_OPT_R_OUTPUT
#% required : no
#%end

import os
import atexit
import string
import grass.script as gscript
from grass.exceptions import CalledModuleError


vrt = """<VRTDataset rasterXSize="$XSIZE" rasterYSize="$YSIZE">
 <SRS>GEOGCS[&quot;wgs84&quot;,DATUM[&quot;WGS_1984&quot;,SPHEROID[&quot;wgs84&quot;,6378137,298.257223563],TOWGS84[0.000,0.000,0.000]],PRIMEM[&quot;Greenwich&quot;,0],UNIT[&quot;degree&quot;,0.0174532925199433]]</SRS>
   <GeoTransform>$WESTCORNER, $RESOLUTION, 0.0000000000000000e+00, $NORTHCORNER, 0.0000000000000e+00, -$RESOLUTION</GeoTransform>
   <VRTRasterBand dataType="Byte" band="1">
    <NoDataValue>0.00000000000000E+00</NoDataValue>
    <ColorInterp>Gray</ColorInterp>
    <SimpleSource>
     <SourceFilename>$FILENAME</SourceFilename>
      <SourceBand>1</SourceBand>
      <SrcRect xOff="0" yOff="0" xSize="$XSIZE" ySize="$YSIZE"/>
      <DstRect xOff="0" yOff="0" xSize="$XSIZE" ySize="$YSIZE"/>
    </SimpleSource>
 </VRTRasterBand>
</VRTDataset>"""

# a function for writing VRT files


def create_VRT_file(projfile, vrtfile, infile):
    fh = open(projfile)
    kv = {}
    for l in fh:
        f = l.rstrip('\r\n').split()
        if f < 2:
            continue
        kv[f[0]] = f[1]
    fh.close()

    north_center = kv['CARTO_UPPER_LEFT_Y']
    # south_center = kv['CARTO_LOWER_LEFT_Y']
    # east_center = kv['CARTO_UPPER_RIGHT_X']
    west_center = kv['CARTO_UPPER_LEFT_X']
    map_proj_res = kv['MAP_PROJ_RESOLUTION']
    xsize = kv['IMAGE_UPPER_RIGHT_COL']
    ysize = kv['IMAGE_LOWER_RIGHT_ROW']

    resolution = float(map_proj_res)
    north_corner = float(north_center) + resolution / 2
    # south_corner = float(south_center) - resolution / 2
    # east_corner = float(east_center) + resolution / 2
    west_corner = float(west_center) - resolution / 2

    t = string.Template(vrt)
    s = t.substitute(NORTHCORNER=north_corner, WESTCORNER=west_corner,
                     XSIZE=xsize, YSIZE=ysize, RESOLUTION=map_proj_res,
                     FILENAME=infile)
    outf = open(vrtfile, 'w')
    outf.write(s)
    outf.close()


def cleanup():
    # clean up the mess
    gscript.try_remove(vrtfile)
    gscript.try_remove(tmpfile)


def main():
    global vrtfile, tmpfile

    infile = options['input']
    rast = options['output']
    also = flags['a']

    # check for gdalinfo (just to check if installation is complete)
    if not gscript.find_program('gdalinfo', '--help'):
        gscript.fatal(_("'gdalinfo' not found, install GDAL tools first "
                        "(http://www.gdal.org)"))

    pid = str(os.getpid())
    tmpfile = gscript.tempfile()

    # let's go

    spotdir = os.path.dirname(infile)
    spotname = gscript.basename(infile, 'hdf')

    if rast:
        name = rast
    else:
        name = spotname

    if not gscript.overwrite() and gscript.find_file(name)['file']:
        gscript.fatal(_("<%s> already exists. Aborting.") % name)

    # still a ZIP file?  (is this portable?? see the r.in.srtm script for
    # ideas)
    if infile.lower().endswith('.zip'):
        gscript.fatal(_("Please extract %s before import.") % infile)

    try:
        p = gscript.Popen(['file', '-ib', infile], stdout=gscript.PIPE)
        s = p.communicate()[0]
        if s == "application/x-zip":
            gscript.fatal(_("Please extract %s before import.") % infile)
    except:
        pass

    # create VRT header for NDVI

    projfile = os.path.join(spotdir, "0001_LOG.TXT")
    vrtfile = tmpfile + '.vrt'

    # first process the NDVI:
    gscript.try_remove(vrtfile)
    create_VRT_file(projfile, vrtfile, infile)

    # let's import the NDVI map...
    gscript.message(_("Importing SPOT VGT NDVI map..."))
    try:
        gscript.run_command('r.in.gdal', input=vrtfile, output=name)
    except CalledModuleError:
        gscript.fatal(_("An error occurred. Stop."))

    gscript.message(_("Imported SPOT VEGETATION NDVI map <%s>.") % name)

    #################
    # http://www.vgt.vito.be/faq/FAQS/faq19.html
    # What is the relation between the digital number and the real NDVI ?
    # Real NDVI =coefficient a * Digital Number + coefficient b
    #           = a * DN +b
    #
    # Coefficient a = 0.004
    # Coefficient b = -0.1

    # clone current region
    # switch to a temporary region
    gscript.use_temp_region()

    gscript.run_command('g.region', raster=name, quiet=True)

    gscript.message(_("Remapping digital numbers to NDVI..."))
    tmpname = "%s_%s" % (name, pid)
    gscript.mapcalc("$tmpname = 0.004 * $name - 0.1", tmpname=tmpname, name=name)
    gscript.run_command('g.remove', type='raster', name=name, quiet=True,
                        flags='f')
    gscript.run_command('g.rename', raster=(tmpname, name), quiet=True)

    # write cmd history:
    gscript.raster_history(name)

    # apply color table:
    gscript.run_command('r.colors', map=name, color='ndvi', quiet=True)

    ##########################
    # second, optionally process the SM quality map:

    # SM Status Map
    # http://nieuw.vgt.vito.be/faq/FAQS/faq22.html
    # Data about
    # Bit NR 7: Radiometric quality for B0 coded as 0 if bad and 1 if good
    # Bit NR 6: Radiometric quality for B2 coded as 0 if bad and 1 if good
    # Bit NR 5: Radiometric quality for B3 coded as 0 if bad and 1 if good
    # Bit NR 4: Radiometric quality for MIR coded as 0 if bad and 1 if good
    # Bit NR 3: land code 1 or water code 0
    # Bit NR 2: ice/snow code 1 , code 0 if there is no ice/snow
    # Bit NR 1:	0	0	1		1
    # Bit NR 0:	0	1	0		1
    # 		clear	shadow	uncertain	cloud
    #
    # Note:
    # pos 7     6    5    4    3    2   1   0 (bit position)
    #   128    64   32   16    8    4   2   1 (values for 8 bit)
    #
    #
    # Bit 4-7 should be 1: their sum is 240
    # Bit 3   land code, should be 1, sum up to 248 along with higher bits
    # Bit 2   ice/snow code
    # Bit 0-1 should be 0
    #
    # A good map threshold: >= 248

    if also:
        gscript.message(_("Importing SPOT VGT NDVI quality map..."))
        gscript.try_remove(vrtfile)
        qname = spotname.replace('NDV', 'SM')
        qfile = os.path.join(spotdir, qname)
        create_VRT_file(projfile, vrtfile, qfile)

        # let's import the SM quality map...
        smfile = name + '.sm'
        try:
            gscript.run_command('r.in.gdal', input=vrtfile, output=smfile)
        except CalledModuleError:
            gscript.fatal(_("An error occurred. Stop."))

        # some of the possible values:
        rules = [r + '\n' for r in ['8 50 50 50',
                                    '11 70 70 70',
                                    '12 90 90 90',
                                    '60 grey',
                                    '155 blue',
                                    '232 violet',
                                    '235 red',
                                    '236 brown',
                                    '248 orange',
                                    '251 yellow',
                                    '252 green']]
        gscript.write_command('r.colors', map=smfile, rules='-', stdin=rules)

        gscript.message(_("Imported SPOT VEGETATION SM quality map <%s>.") %
                        smfile)
        gscript.message(_("Note: A snow map can be extracted by category "
                          "252 (d.rast %s cat=252)") % smfile)
        gscript.message("")
        gscript.message(_("Filtering NDVI map by Status Map quality layer..."))

        filtfile = "%s_filt" % name
        gscript.mapcalc("$filtfile = if($smfile % 4 == 3 || "
                        "($smfile / 16) % 16 == 0, null(), $name)",
                        filtfile=filtfile, smfile=smfile, name=name)
        gscript.run_command('r.colors', map=filtfile, color='ndvi', quiet=True)
        gscript.message(_("Filtered SPOT VEGETATION NDVI map <%s>.") %
                        filtfile)

        # write cmd history:
        gscript.raster_history(smfile)
        gscript.raster_history(filtfile)

    gscript.message(_("Done."))

if __name__ == "__main__":
    options, flags = gscript.parser()
    atexit.register(cleanup)
    main()
