#!/usr/bin/env python
############################################################################
#  imagecomp.py
#
#  Copyright 2017 RSGISLib.
#
#  RSGISLib: 'The remote sensing and GIS Software Library'
#
#  RSGISLib is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  RSGISLib is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with RSGISLib.  If not, see <http://www.gnu.org/licenses/>.
#
#
# Purpose:  Provide a set of utilities for creating image composites
#
# Author: Pete Bunting
# Email: petebunting@mac.com
# Date: 04/10/2017
# Version: 1.0
#
# History:
# Version 1.0 - Created.
#
############################################################################

import glob
import os
import os.path
import numpy
import shutil

import osgeo.gdal
import rios.rat

import rsgislib
import rsgislib.imagecalc
import rsgislib.imagecalc.calcindices
import rsgislib.imageutils
import rsgislib.rastergis


def create_max_ndvi_composite(
    in_imgs_pattern,
    r_band,
    n_band,
    out_ref_img,
    out_comp_img,
    tmp_dir="tmp",
    gdalformat="KEA",
    datatype=None,
    calc_stats=True,
):
    """
    Create an image composite from multiple input images where the pixel brought through into the composite is the one with
    the maximum NDVI.

    :param in_imgs_pattern: is a pattern (ready for glob.glob(inImgsPattern)) so needs an '*' within the pattern to find the input image files.
    :param r_band: is the image band within the input images (same for all) for the red band - note band indexing starts at 1.
    :param n_band: is the image band within the input images (same for all) for the nir band - note band indexing starts at 1.
    :param out_ref_img: is the output reference image which details which input image is forming the output image pixel value (Note. this file will always be a KEA file as RAT is used).
    :param out_comp_img: is the output composite image for which gdalformat and dataType define the format and data type.
    :param tmp_dir: is a temp path for intemediate files, if this path doesn't exist is will be created and deleted at runtime.
    :param gdalformat: is the output file format of the outCompImg, any GDAL compatable format is OK (Defaut is KEA).
    :param datatype: is the data type of the output image (outCompImg). If None is provided then the data type of the first input image will be used (Default None).
    :param calc_stats: calculate image statics and pyramids (Default=True)

    """
    import rsgislib.tools.utils

    uidStr = rsgislib.tools.utils.uid_generator()

    # Get List of input images:
    inImages = glob.glob(in_imgs_pattern)

    if len(inImages) > 1:
        tmpPresent = True
        if not os.path.exists(tmp_dir):
            os.makedirs(tmp_dir)
            tmpPresent = False

        refLayersPath = os.path.join(tmp_dir, "RefLyrs_" + uidStr)

        refImgTmpPresent = True
        if not os.path.exists(refLayersPath):
            os.makedirs(refLayersPath)
            refImgTmpPresent = False

        if datatype is None:
            datatype = rsgislib.imageutils.get_rsgislib_datatype_from_img(inImages[0])

        numInLyrs = len(inImages)

        numpy.random.seed(5)
        red = numpy.random.randint(1, 255, numInLyrs + 1, int)
        red[0] = 0
        numpy.random.seed(2)
        green = numpy.random.randint(1, 255, numInLyrs + 1, int)
        green[0] = 0
        numpy.random.seed(9)
        blue = numpy.random.randint(1, 255, numInLyrs + 1, int)
        blue[0] = 0
        alpha = numpy.zeros_like(blue)
        alpha[...] = 255
        imgLyrs = numpy.empty(numInLyrs + 1, dtype=numpy.dtype("a255"))

        # Generate Comp Ref layers:
        refLyrsLst = []
        idx = 1
        for img in inImages:
            print("In Image (" + str(idx) + "):\t" + img)
            imgLyrs[idx] = os.path.basename(img)
            baseImgName = os.path.splitext(os.path.basename(img))[0]
            refLyrImg = os.path.join(refLayersPath, baseImgName + "_ndvi.kea")
            rsgislib.imagecalc.calcindices.calc_ndvi(
                img, r_band, n_band, refLyrImg, False
            )
            refLyrsLst.append(refLyrImg)
            idx = idx + 1
        imgLyrs[0] = ""

        # Create REF Image
        rsgislib.imagecalc.get_img_idx_for_stat(
            refLyrsLst, out_ref_img, "KEA", -999, rsgislib.SUMTYPE_MAX
        )
        if calc_stats:
            # Pop Ref Image with stats
            rsgislib.rastergis.pop_rat_img_stats(out_ref_img, True, True, True)

            # Open the clumps dataset as a gdal dataset
            ratDataset = osgeo.gdal.Open(out_ref_img, osgeo.gdal.GA_Update)

            # Write colours to RAT
            rios.rat.writeColumn(ratDataset, "Red", red)
            rios.rat.writeColumn(ratDataset, "Green", green)
            rios.rat.writeColumn(ratDataset, "Blue", blue)
            rios.rat.writeColumn(ratDataset, "Alpha", alpha)
            rios.rat.writeColumn(ratDataset, "Image", imgLyrs)

            ratDataset = None

        # Create Composite Image
        rsgislib.imageutils.create_ref_img_composite_img(
            inImages, out_comp_img, out_ref_img, gdalformat, datatype, 0.0
        )

        if calc_stats:
            # Calc Stats
            rsgislib.imageutils.pop_img_stats(
                out_comp_img, use_no_data=True, no_data_val=0, calc_pyramids=True
            )

        if not refImgTmpPresent:
            shutil.rmtree(refLayersPath, ignore_errors=True)

        if not tmpPresent:
            shutil.rmtree(tmp_dir, ignore_errors=True)
    elif len(inImages) == 1:
        print("Only 1 Input Image, Just Copying File to output")
        shutil.copy(inImages[0], out_comp_img)
    else:
        raise rsgislib.RSGISPyException(
            "There were no input images for " + in_imgs_pattern
        )


def create_max_ndvi_ndwi_composite_landsat(
    inImgsPattern,
    outRefImg,
    outCompImg,
    outMskImg,
    tmpPath="tmp",
    gdalformat="KEA",
    dataType=None,
    calcStats=True,
    use_mode=True,
):
    """
    Create an image composite from multiple input images where the pixel brought through into the composite is the one with
    the maximum NDVI over land and NDWI over water. A mask of land and water regions is also produced. Landsat 8 images are
    identified as image file names are expected to start 'LS8'. If composite includes a mix of LS8 and LS7 images then the
    LS8 images are submitted to match the images bands of LS7 (i.e., coastal band removed).

    :param inImgsPattern: is a pattern (ready for glob.glob(inImgsPattern)) so needs an '*' within the pattern to find the input image files.
    :param outRefImg: is the output reference image which details which input image is forming the output image pixel value (Note. this file will always be a KEA file as RAT is used).
    :param outCompImg: is the output composite image for which gdalformat and dataType define the format and data type.
    :param outMskImg: is the output mask image for regions of water and land where ndvi vs ndwi are used (0=nodata, 1=land, 2=water)
    :param tmpPath: is a temp path for intemediate files, if this path doesn't exist is will be created and deleted at runtime.
    :param gdalformat: is the output file format of the outCompImg, any GDAL compatable format is OK (Defaut is KEA).
    :param dataType: is the data type of the output image (outCompImg). If None is provided then the data type of the first input image will be used (Default None).
    :param calcStats: calculate image statics and pyramids (Default=True)
    :param use_mode: True: the land/water masks are combined using the mode and False: the land water masks are combined using median.

    """
    import rsgislib.tools.utils

    uidStr = rsgislib.tools.utils.uid_generator()

    # Get List of input images:
    inImages = glob.glob(inImgsPattern)

    if len(inImages) > 1:
        tmpPresent = True
        if not os.path.exists(tmpPath):
            os.makedirs(tmpPath)
            tmpPresent = False

        refLayersPath = os.path.join(tmpPath, "RefLyrs_" + uidStr)

        refImgTmpPresent = True
        if not os.path.exists(refLayersPath):
            os.makedirs(refLayersPath)
            refImgTmpPresent = False

        if dataType is None:
            dataType = rsgislib.imageutils.get_rsgislib_datatype_from_img(inImages[0])

        numInLyrs = len(inImages)

        numpy.random.seed(5)
        red = numpy.random.randint(1, 255, numInLyrs + 1, int)
        red[0] = 0
        numpy.random.seed(2)
        green = numpy.random.randint(1, 255, numInLyrs + 1, int)
        green[0] = 0
        numpy.random.seed(9)
        blue = numpy.random.randint(1, 255, numInLyrs + 1, int)
        blue[0] = 0
        alpha = numpy.zeros_like(blue)
        alpha[...] = 255
        imgLyrs = numpy.empty(numInLyrs + 1, dtype=numpy.dtype("a255"))

        # Generate Comp Ref layers:
        landWaterMskBandDefns = []
        mskImgs = []
        idx = 1
        onlyLS8 = True
        incLS8 = False
        for img in inImages:
            print("In Image (" + str(idx) + "):\t" + img)
            imgLyrs[idx] = os.path.basename(img)
            baseImgName = os.path.splitext(os.path.basename(img))[0]
            refLyrNDVIImg = os.path.join(refLayersPath, baseImgName + "_ndvi.kea")
            refLyrNDWIImg = os.path.join(refLayersPath, baseImgName + "_ndwi.kea")
            if "LS8" in img:
                rBand = 4
                nBand = 5
                sBand = 6
                incLS8 = True
            else:
                rBand = 3
                nBand = 4
                sBand = 5
                onlyLS8 = False

            rsgislib.imagecalc.calcindices.calc_ndvi(
                img, rBand, nBand, refLyrNDVIImg, False
            )
            rsgislib.imagecalc.calcindices.calc_ndwi(
                img, nBand, sBand, refLyrNDWIImg, False
            )

            refLyrMskImg = os.path.join(
                refLayersPath, baseImgName + "_waterLandMsk.kea"
            )
            bandDefns = []
            bandDefns.append(rsgislib.imagecalc.BandDefn("ndvi", refLyrNDVIImg, 1))
            bandDefns.append(rsgislib.imagecalc.BandDefn("ndwi", refLyrNDWIImg, 1))
            rsgislib.imagecalc.band_math(
                refLyrMskImg,
                "ndvi<-1?0:ndvi>0.3?1:ndwi>0.01?2:1",
                "KEA",
                rsgislib.TYPE_8UINT,
                bandDefns,
            )
            mskImgs.append(refLyrMskImg)
            idx = idx + 1
        imgLyrs[0] = ""

        refLyrMskStackImg = os.path.join(
            refLayersPath, uidStr + "_waterLandMskStack.kea"
        )
        rsgislib.imageutils.stack_img_bands(
            mskImgs, None, refLyrMskStackImg, -1, -1, "KEA", rsgislib.TYPE_8UINT
        )
        if use_mode:
            rsgislib.imagecalc.imagePixelColumnSummary(
                refLyrMskStackImg,
                outMskImg,
                rsgislib.imagecalc.StatsSummary(calcMode=True),
                "KEA",
                rsgislib.TYPE_8UINT,
                0,
                True,
            )
        else:
            rsgislib.imagecalc.imagePixelColumnSummary(
                refLyrMskStackImg,
                outMskImg,
                rsgislib.imagecalc.StatsSummary(calcMedian=True),
                "KEA",
                rsgislib.TYPE_8UINT,
                0,
                True,
            )
        rsgislib.rastergis.pop_rat_img_stats(outMskImg, True, True, True)

        idx = 1
        refLyrsLst = []
        for img in inImages:
            print("In Image (" + str(idx) + "):\t" + img)
            baseImgName = os.path.splitext(os.path.basename(img))[0]
            refLyrNDVIImg = os.path.join(refLayersPath, baseImgName + "_ndvi.kea")
            refLyrNDWIImg = os.path.join(refLayersPath, baseImgName + "_ndwi.kea")
            refLyrLclMskImg = os.path.join(
                refLayersPath, baseImgName + "_waterLandMsk.kea"
            )

            refLyrImg = os.path.join(refLayersPath, baseImgName + "_refHybrid.kea")
            bandDefns = []
            bandDefns.append(rsgislib.imagecalc.BandDefn("lmsk", refLyrLclMskImg, 1))
            bandDefns.append(rsgislib.imagecalc.BandDefn("omsk", outMskImg, 1))
            bandDefns.append(rsgislib.imagecalc.BandDefn("ndvi", refLyrNDVIImg, 1))
            bandDefns.append(rsgislib.imagecalc.BandDefn("ndwi", refLyrNDWIImg, 1))
            rsgislib.imagecalc.band_math(
                refLyrImg,
                "lmsk==0?-999:omsk==1?ndvi:omsk==2?ndwi:-999",
                "KEA",
                rsgislib.TYPE_32FLOAT,
                bandDefns,
            )
            refLyrsLst.append(refLyrImg)
            idx = idx + 1

        if incLS8 and (not onlyLS8):
            inImagesTmp = []
            for img in inImages:
                if "LS8" in img:
                    baseImgName = os.path.splitext(os.path.basename(img))[0]
                    reflSubImg = os.path.join(tmpPath, baseImgName + "_bandsub.kea")
                    rsgislib.imageutils.select_img_bands(
                        img, reflSubImg, "KEA", dataType, [2, 3, 4, 5, 6, 7]
                    )
                    inImagesTmp.append(reflSubImg)
                else:
                    inImagesTmp.append(img)
            inImages = inImagesTmp

        # Create REF Image
        rsgislib.imagecalc.get_img_idx_for_stat(
            refLyrsLst, outRefImg, "KEA", -999, rsgislib.SUMTYPE_MAX
        )
        if calcStats:
            # Pop Ref Image with stats
            rsgislib.rastergis.pop_rat_img_stats(outRefImg, True, True, True)

            # Open the clumps dataset as a gdal dataset
            ratDataset = osgeo.gdal.Open(outRefImg, osgeo.gdal.GA_Update)
            # Write colours to RAT
            rios.rat.writeColumn(ratDataset, "Red", red)
            rios.rat.writeColumn(ratDataset, "Green", green)
            rios.rat.writeColumn(ratDataset, "Blue", blue)
            rios.rat.writeColumn(ratDataset, "Alpha", alpha)
            rios.rat.writeColumn(ratDataset, "Image", imgLyrs)
            ratDataset = None

        # Create Composite Image
        rsgislib.imageutils.create_ref_img_composite_img(
            inImages, outCompImg, outRefImg, gdalformat, dataType, 0.0
        )

        if calcStats:
            # Calc Stats
            rsgislib.imageutils.pop_img_stats(
                outCompImg, use_no_data=True, no_data_val=0, calc_pyramids=True
            )

        if not refImgTmpPresent:
            shutil.rmtree(refLayersPath, ignore_errors=True)

        if not tmpPresent:
            shutil.rmtree(tmpPath, ignore_errors=True)

    elif len(inImages) == 1:
        print("Only 1 Input Image, Just Copying File to output")
        shutil.copy(inImages[0], outCompImg)
    else:
        raise rsgislib.RSGISPyException(
            "There were no input images for " + inImgsPattern
        )


def check_build_ls8_vrts(input_imgs, output_dir):
    """
    A function which checks for Landsat 8 (LS8) images in the input list and creates
    a band subset (i.e., removes the coastal (1) band). This function should be used
    ahead of create_max_ndvi_ndwi_composite when combining LS8 with earlier landsat
    (i.e., LS5 and LS7) data. Note, files who's file name contain 'LS8' are considered
    to be Landsat 8 images.

    :param input_imgs: input list of image file paths.
    :param output_dir: output directory for the VRT images (Note. an absolute path to
                   the input image is used when building the VRT.)
    """
    import rsgislib.tools.filetools

    img_bands = [2, 3, 4, 5, 6, 7]
    out_imgs = []
    for img in input_imgs:
        if "LS8" in os.path.basename(img):
            abs_img = os.path.abspath(img)
            basename = rsgislib.tools.filetools.get_file_basename(img)
            out_vrt_img = os.path.join(output_dir, f"{basename}_bsub.vrt")
            rsgislib.imageutils.create_vrt_band_subset(abs_img, img_bands, out_vrt_img)
            out_imgs.append(out_vrt_img)
        else:
            out_imgs.append(img)
    return out_imgs


def create_max_ndvi_ndwi_composite(
    refImg,
    inImages,
    rBand,
    nBand,
    sBand,
    outRefImg,
    outCompImg,
    outMskImg,
    tmpPath="tmp",
    gdalformat="KEA",
    dataType=None,
    calcStats=True,
    reprojmethod="cubic",
    use_mode=True,
):
    """
    Create an image composite from multiple input images where the pixel brought through into the composite is the one with
    the maximum NDVI over land and NDWI over water. A mask of land and water regions is also produced. The reference image is
    used to define the spatial extent of the output images and spatial projection.

    :param refImg: is a reference image with any number of bands and data type which is used to define the output image extent and projection.
    :param inImages: a list of all the input images being used to build the composite.
    :param rBand: is an integer specifying the red band in the input images (starts at 1), used in the NDVI index.
    :param nBand: is an integer specifying the NIR band in the input images (starts at 1), used in the NDVI and NDWI index.
    :param sBand: is an integer specifying the SWIR band in the input images (starts at 1), used in the NDVI and NDWI index.
    :param outRefImg: is the output reference image which details which input image is forming the output image pixel value (Note. this file will always be a KEA file as RAT is used).
    :param outCompImg: is the output composite image for which gdalformat and dataType define the format and data type.
    :param outMskImg: is the output mask image for regions of water and land where ndvi vs ndwi are used (0=nodata, 1=land, 2=water)
    :param tmpPath: is a temp path for intemediate files, if this path doesn't exist is will be created and deleted at runtime.
    :param gdalformat: is the output file format of the outCompImg, any GDAL compatable format is OK (Defaut is KEA).
    :param dataType: is the data type of the output image (outCompImg). If None is provided then the data type of the first input image will be used (Default None).
    :param calcStats: calculate image statics and pyramids (Default=True)
    :param reprojmethod: specifies the interpolation method used to reproject the input images which are in a different projection and/or pixel size as the reference image (default: cubic).
    :param use_mode: True: the land/water masks are combined using the mode and False: the land water masks are combined using median.

    """
    import rsgislib.tools.utils

    uidStr = rsgislib.tools.utils.uid_generator()

    if len(inImages) > 1:
        init_in_images = inImages
        inImagesOverlap = []
        inImages2ReProj = []
        inImagesSub2Ref = []
        nBands = 0
        first = True
        for img in init_in_images:
            if first:
                nBands = rsgislib.imageutils.get_img_band_count(img)
                first = False
            else:
                cBands = rsgislib.imageutils.get_img_band_count(img)
                if cBands != nBands:
                    raise rsgislib.RSGISPyException(
                        "The number of image bands is not consistent (Bands: {0} and {1})".format(
                            nBands, cBands
                        )
                    )

            sameProj = rsgislib.imageutils.do_gdal_layers_have_same_proj(refImg, img)
            if rsgislib.imageutils.doImagesOverlap(refImg, img):
                if sameProj:
                    if rsgislib.imageutils.doImageResMatch(refImg, img):
                        inImagesOverlap.append(img)
                    else:
                        inImages2ReProj.append(img)
                else:
                    inImages2ReProj.append(img)

        nImgs = len(inImagesOverlap) + len(inImages2ReProj)
        print("There are {} images with overlap to create the composite.".format(nImgs))
        if nImgs > 1:
            if dataType is None:
                if len(inImagesOverlap) > 0:
                    dataType = rsgislib.imageutils.get_rsgislib_datatype_from_img(
                        inImagesOverlap[0]
                    )
                else:
                    dataType = rsgislib.imageutils.get_rsgislib_datatype_from_img(
                        inImages2ReProj[0]
                    )

            tmpPresent = True
            if not os.path.exists(tmpPath):
                os.makedirs(tmpPath)
                tmpPresent = False

            subsetImgTmpPresent = True
            if len(inImagesOverlap) > 0:
                print("Subset images to reference extent.")
                subsetLayersPath = os.path.join(tmpPath, "Subset_" + uidStr)
                if not os.path.exists(subsetLayersPath):
                    os.makedirs(subsetLayersPath)
                    subsetImgTmpPresent = False

                for img in inImagesOverlap:
                    basename = os.path.splitext(os.path.basename(img))[0]
                    outImg = os.path.join(subsetLayersPath, basename + "_subset.kea")
                    rsgislib.imageutils.create_copy_img(
                        refImg, outImg, nBands, 0, "KEA", dataType
                    )
                    rsgislib.imageutils.includeImagesIndImgIntersect(outImg, [img])
                    inImagesSub2Ref.append(outImg)

            reprojImgTmpPresent = True
            if len(inImages2ReProj) > 0:
                print("Reproject images to reference extent.")
                reprojLayersPath = os.path.join(tmpPath, "Reproj_" + uidStr)
                if not os.path.exists(reprojLayersPath):
                    os.makedirs(reprojLayersPath)
                    reprojImgTmpPresent = False

                for img in inImages2ReProj:
                    basename = os.path.splitext(os.path.basename(img))[0]
                    outImg = os.path.join(reprojLayersPath, basename + "_reproj.kea")
                    rsgislib.imageutils.resampleImage2Match(
                        refImg, img, outImg, "KEA", reprojmethod, dataType
                    )
                    inImagesSub2Ref.append(outImg)

            refLayersPath = os.path.join(tmpPath, "RefLyrs_" + uidStr)
            refImgTmpPresent = True
            if not os.path.exists(refLayersPath):
                os.makedirs(refLayersPath)
                refImgTmpPresent = False

            numInLyrs = len(inImagesSub2Ref)

            numpy.random.seed(5)
            red = numpy.random.randint(1, 255, numInLyrs + 1, int)
            red[0] = 0
            numpy.random.seed(2)
            green = numpy.random.randint(1, 255, numInLyrs + 1, int)
            green[0] = 0
            numpy.random.seed(9)
            blue = numpy.random.randint(1, 255, numInLyrs + 1, int)
            blue[0] = 0
            alpha = numpy.zeros_like(blue)
            alpha[...] = 255
            imgLyrs = numpy.empty(numInLyrs + 1, dtype=numpy.dtype("a255"))

            # Generate Comp Ref layers:
            landWaterMskBandDefns = []
            mskImgs = []
            idx = 1
            for img in inImagesSub2Ref:
                print("In Image (" + str(idx) + "):\t" + img)
                imgLyrs[idx] = os.path.basename(img)
                baseImgName = os.path.splitext(os.path.basename(img))[0]
                refLyrNDVIImg = os.path.join(refLayersPath, baseImgName + "_ndvi.kea")
                refLyrNDWIImg = os.path.join(refLayersPath, baseImgName + "_ndwi.kea")
                rsgislib.imagecalc.calcindices.calc_ndvi(
                    img, rBand, nBand, refLyrNDVIImg, False
                )
                rsgislib.imagecalc.calcindices.calc_ndwi(
                    img, nBand, sBand, refLyrNDWIImg, False
                )

                refLyrMskImg = os.path.join(
                    refLayersPath, baseImgName + "_waterLandMsk.kea"
                )
                bandDefns = []
                bandDefns.append(rsgislib.imagecalc.BandDefn("ndvi", refLyrNDVIImg, 1))
                bandDefns.append(rsgislib.imagecalc.BandDefn("ndwi", refLyrNDWIImg, 1))
                rsgislib.imagecalc.band_math(
                    refLyrMskImg,
                    "ndvi<-1?0:ndvi>0.3?1:ndwi>0.01?2:1",
                    "KEA",
                    rsgislib.TYPE_8UINT,
                    bandDefns,
                )
                mskImgs.append(refLyrMskImg)
                idx = idx + 1
            imgLyrs[0] = ""

            refLyrMskStackImg = os.path.join(
                refLayersPath, uidStr + "_waterLandMskStack.kea"
            )
            rsgislib.imageutils.stack_img_bands(
                mskImgs, None, refLyrMskStackImg, -1, -1, "KEA", rsgislib.TYPE_8UINT
            )
            if use_mode:
                rsgislib.imagecalc.imagePixelColumnSummary(
                    refLyrMskStackImg,
                    outMskImg,
                    rsgislib.imagecalc.StatsSummary(calcMode=True),
                    "KEA",
                    rsgislib.TYPE_8UINT,
                    0,
                    True,
                )
            else:
                rsgislib.imagecalc.imagePixelColumnSummary(
                    refLyrMskStackImg,
                    outMskImg,
                    rsgislib.imagecalc.StatsSummary(calcMedian=True),
                    "KEA",
                    rsgislib.TYPE_8UINT,
                    0,
                    True,
                )
            rsgislib.rastergis.pop_rat_img_stats(outMskImg, True, True, True)

            idx = 1
            refLyrsLst = []
            for img in inImagesSub2Ref:
                print("In Image (" + str(idx) + "):\t" + img)
                baseImgName = os.path.splitext(os.path.basename(img))[0]
                refLyrNDVIImg = os.path.join(refLayersPath, baseImgName + "_ndvi.kea")
                refLyrNDWIImg = os.path.join(refLayersPath, baseImgName + "_ndwi.kea")
                refLyrLclMskImg = os.path.join(
                    refLayersPath, baseImgName + "_waterLandMsk.kea"
                )

                refLyrImg = os.path.join(refLayersPath, baseImgName + "_refHybrid.kea")
                bandDefns = []
                bandDefns.append(
                    rsgislib.imagecalc.BandDefn("lmsk", refLyrLclMskImg, 1)
                )
                bandDefns.append(rsgislib.imagecalc.BandDefn("omsk", outMskImg, 1))
                bandDefns.append(rsgislib.imagecalc.BandDefn("ndvi", refLyrNDVIImg, 1))
                bandDefns.append(rsgislib.imagecalc.BandDefn("ndwi", refLyrNDWIImg, 1))
                rsgislib.imagecalc.band_math(
                    refLyrImg,
                    "lmsk==0?-999:omsk==1?ndvi:omsk==2?ndwi:-999",
                    "KEA",
                    rsgislib.TYPE_32FLOAT,
                    bandDefns,
                )
                refLyrsLst.append(refLyrImg)
                idx = idx + 1

            # Create REF Image
            rsgislib.imagecalc.get_img_idx_for_stat(
                refLyrsLst, outRefImg, "KEA", -999, rsgislib.SUMTYPE_MAX
            )
            if calcStats:
                # Pop Ref Image with stats
                rsgislib.rastergis.pop_rat_img_stats(outRefImg, True, True, True)

                # Open the clumps dataset as a gdal dataset
                ratDataset = osgeo.gdal.Open(outRefImg, osgeo.gdal.GA_Update)
                # Write colours to RAT
                rios.rat.writeColumn(ratDataset, "Red", red)
                rios.rat.writeColumn(ratDataset, "Green", green)
                rios.rat.writeColumn(ratDataset, "Blue", blue)
                rios.rat.writeColumn(ratDataset, "Alpha", alpha)
                rios.rat.writeColumn(ratDataset, "Image", imgLyrs)
                ratDataset = None

            # Create Composite Image
            rsgislib.imageutils.create_ref_img_composite_img(
                inImagesSub2Ref, outCompImg, outRefImg, gdalformat, dataType, 0.0
            )

            if calcStats:
                # Calc Stats
                rsgislib.imageutils.pop_img_stats(
                    outCompImg, use_no_data=True, no_data_val=0, calc_pyramids=True
                )

            if not refImgTmpPresent:
                shutil.rmtree(refLayersPath, ignore_errors=True)

            if not subsetImgTmpPresent:
                shutil.rmtree(subsetLayersPath, ignore_errors=True)

            if not reprojImgTmpPresent:
                shutil.rmtree(reprojLayersPath, ignore_errors=True)

            if not tmpPresent:
                shutil.rmtree(tmpPath, ignore_errors=True)
        else:
            raise rsgislib.RSGISPyException(
                "There were only {0} images which intersect with the reference image.".format(
                    nImgs
                )
            )

    elif len(inImages) == 1:
        print("Only 1 Input Image, Just Copying File to output")
        nBands = rsgislib.imageutils.get_img_band_count(inImages[0])
        if dataType is None:
            dataType = rsgislib.imageutils.get_rsgislib_datatype_from_img(inImages[0])
        rsgislib.imageutils.create_copy_img(
            refImg, outCompImg, nBands, 0, gdalformat, dataType
        )
        rsgislib.imageutils.includeImagesIndImgIntersect(outCompImg, [inImages[0]])
    else:
        raise rsgislib.RSGISPyException("List of input images was empty ")


def create_max_scaled_ndvi_ndwi_composite(
    refImg,
    inImages,
    gBand,
    rBand,
    nBand,
    sBand,
    outRefImg,
    outCompImg,
    outMskImg,
    tmpPath="tmp",
    gdalformat="KEA",
    dataType=None,
    calcStats=True,
    reprojmethod="cubic",
    use_mode=True,
):
    """
    Create an image composite from multiple input images where the pixel brought through into the composite is the one with
    the maximum NDVI over land and NDWI over water. A mask of land and water regions is also produced. The reference image is
    used to define the spatial extent of the output images and spatial projection.

    :param refImg: is a reference image with any number of bands and data type which is used to define the output image extent and projection.
    :param inImages: a list of all the input images being used to build the composite.
    :param gBand: is an integer specifying the green band in the input images (starts at 1), used in the GNDWI index.
    :param rBand: is an integer specifying the red band in the input images (starts at 1), used in the NDVI index.
    :param nBand: is an integer specifying the NIR band in the input images (starts at 1), used in the NDVI, GNDWI and NDWI index.
    :param sBand: is an integer specifying the SWIR band in the input images (starts at 1), used in the NDVI and NDWI index.
    :param outRefImg: is the output reference image which details which input image is forming the output image pixel value (Note. this file will always be a KEA file as RAT is used).
    :param outCompImg: is the output composite image for which gdalformat and dataType define the format and data type.
    :param outMskImg: is the output mask image for regions of water and land where ndvi vs ndwi are used (0=nodata, 1=land, 2=water)
    :param tmpPath: is a temp path for intemediate files, if this path doesn't exist is will be created and deleted at runtime.
    :param gdalformat: is the output file format of the outCompImg, any GDAL compatable format is OK (Defaut is KEA).
    :param dataType: is the data type of the output image (outCompImg). If None is provided then the data type of the first input image will be used (Default None).
    :param calcStats: calculate image statics and pyramids (Default=True)
    :param reprojmethod: specifies the interpolation method used to reproject the input images which are in a different projection and/or pixel size as the reference image (default: cubic).
    :param use_mode: True: the land/water masks are combined using the mode and False: the land water masks are combined using median.

    """
    import rsgislib.tools.utils

    uidStr = rsgislib.tools.utils.uid_generator()

    if len(inImages) > 1:
        init_in_images = inImages
        inImagesOverlap = []
        inImages2ReProj = []
        inImagesSub2Ref = []
        nBands = 0
        first = True
        for img in init_in_images:
            if first:
                nBands = rsgislib.imageutils.get_img_band_count(img)
                first = False
            else:
                cBands = rsgislib.imageutils.get_img_band_count(img)
                if cBands != nBands:
                    raise rsgislib.RSGISPyException(
                        "The number of image bands is not consistent (Bands: {0} and {1})".format(
                            nBands, cBands
                        )
                    )

            sameProj = rsgislib.imageutils.do_gdal_layers_have_same_proj(refImg, img)
            if rsgislib.imageutils.doImagesOverlap(refImg, img):
                if sameProj:
                    if rsgislib.imageutils.doImageResMatch(refImg, img):
                        inImagesOverlap.append(img)
                    else:
                        inImages2ReProj.append(img)
                else:
                    inImages2ReProj.append(img)

        nImgs = len(inImagesOverlap) + len(inImages2ReProj)
        print("There are {} images with overlap to create the composite.".format(nImgs))
        if nImgs > 1:
            if dataType is None:
                if len(inImagesOverlap) > 0:
                    dataType = rsgislib.imageutils.get_rsgislib_datatype_from_img(
                        inImagesOverlap[0]
                    )
                else:
                    dataType = rsgislib.imageutils.get_rsgislib_datatype_from_img(
                        inImages2ReProj[0]
                    )

            tmpPresent = True
            if not os.path.exists(tmpPath):
                os.makedirs(tmpPath)
                tmpPresent = False

            subsetImgTmpPresent = True
            if len(inImagesOverlap) > 0:
                print("Subset images to reference extent.")
                subsetLayersPath = os.path.join(tmpPath, "Subset_" + uidStr)
                if not os.path.exists(subsetLayersPath):
                    os.makedirs(subsetLayersPath)
                    subsetImgTmpPresent = False

                for img in inImagesOverlap:
                    basename = os.path.splitext(os.path.basename(img))[0]
                    outImg = os.path.join(subsetLayersPath, basename + "_subset.kea")
                    rsgislib.imageutils.create_copy_img(
                        refImg, outImg, nBands, 0, "KEA", dataType
                    )
                    rsgislib.imageutils.includeImagesIndImgIntersect(outImg, [img])
                    inImagesSub2Ref.append(outImg)

            reprojImgTmpPresent = True
            if len(inImages2ReProj) > 0:
                print("Reproject images to reference extent.")
                reprojLayersPath = os.path.join(tmpPath, "Reproj_" + uidStr)
                if not os.path.exists(reprojLayersPath):
                    os.makedirs(reprojLayersPath)
                    reprojImgTmpPresent = False

                for img in inImages2ReProj:
                    basename = os.path.splitext(os.path.basename(img))[0]
                    outImg = os.path.join(reprojLayersPath, basename + "_reproj.kea")
                    rsgislib.imageutils.resampleImage2Match(
                        refImg, img, outImg, "KEA", reprojmethod, dataType
                    )
                    inImagesSub2Ref.append(outImg)

            refLayersPath = os.path.join(tmpPath, "RefLyrs_" + uidStr)
            refImgTmpPresent = True
            if not os.path.exists(refLayersPath):
                os.makedirs(refLayersPath)
                refImgTmpPresent = False

            numInLyrs = len(inImagesSub2Ref)

            numpy.random.seed(5)
            red = numpy.random.randint(1, 255, numInLyrs + 1, int)
            red[0] = 0
            numpy.random.seed(2)
            green = numpy.random.randint(1, 255, numInLyrs + 1, int)
            green[0] = 0
            numpy.random.seed(9)
            blue = numpy.random.randint(1, 255, numInLyrs + 1, int)
            blue[0] = 0
            alpha = numpy.zeros_like(blue)
            alpha[...] = 255
            imgLyrs = numpy.empty(numInLyrs + 1, dtype=numpy.dtype("a255"))

            # Generate Comp Ref layers:
            landWaterMskBandDefns = []
            mskImgs = []
            idx = 1
            for img in inImagesSub2Ref:
                print("In Image (" + str(idx) + "):\t" + img)
                imgLyrs[idx] = os.path.basename(img)
                baseImgName = os.path.splitext(os.path.basename(img))[0]
                refLyrNDVIImg = os.path.join(refLayersPath, baseImgName + "_ndvi.kea")
                refLyrNDWIImg = os.path.join(refLayersPath, baseImgName + "_ndwi.kea")
                ###refLyrGNDWIImg = os.path.join(refLayersPath, baseImgName+'_gndwi.kea')
                ###refLyrGMNDWIImg = os.path.join(refLayersPath, baseImgName+'_gmndwi.kea')
                rsgislib.imagecalc.calcindices.calc_ndvi(
                    img, rBand, nBand, refLyrNDVIImg, False
                )
                rsgislib.imagecalc.calcindices.calc_ndwi(
                    img, nBand, sBand, refLyrNDWIImg, False
                )
                ###rsgislib.imagecalc.calcindices.calc_gndwi(img, gBand, nBand, refLyrGNDWIImg, False)
                ###rsgislib.imagecalc.calcindices.calc_gmndwi(img, gBand, sBand, refLyrGMNDWIImg, False)

                refLyrMskImg = os.path.join(
                    refLayersPath, baseImgName + "_waterLandMsk.kea"
                )
                bandDefns = []
                bandDefns.append(rsgislib.imagecalc.BandDefn("ndvi", refLyrNDVIImg, 1))
                bandDefns.append(rsgislib.imagecalc.BandDefn("ndwi", refLyrNDWIImg, 1))
                ###bandDefns.append(rsgislib.imagecalc.BandDefn('gndwi', refLyrGNDWIImg, 1))
                ###bandDefns.append(rsgislib.imagecalc.BandDefn('gmndwi', refLyrGMNDWIImg, 1))
                ###rsgislib.imagecalc.band_math(refLyrMskImg, '(ndvi<-999)?0:(ndvi>0.3)?1:(ndwi>0.01)?2:(gndwi>0.01)?2:(gmndwi>0.01)?2:1', 'KEA', rsgislib.TYPE_8UINT, bandDefns)
                rsgislib.imagecalc.band_math(
                    refLyrMskImg,
                    "(ndvi==-999)?0:(ndvi>0.3)?1:(ndwi>0.01)?2:1",
                    "KEA",
                    rsgislib.TYPE_8UINT,
                    bandDefns,
                )
                mskImgs.append(refLyrMskImg)
                idx = idx + 1
            imgLyrs[0] = ""

            print("Creating land/Water mask.")
            refLyrMskStackImg = os.path.join(
                refLayersPath, uidStr + "_waterLandMskStack.kea"
            )
            rsgislib.imageutils.stack_img_bands(
                mskImgs, None, refLyrMskStackImg, -1, -1, "KEA", rsgislib.TYPE_8UINT
            )
            if use_mode:
                rsgislib.imagecalc.imagePixelColumnSummary(
                    refLyrMskStackImg,
                    outMskImg,
                    rsgislib.imagecalc.StatsSummary(calcMode=True),
                    "KEA",
                    rsgislib.TYPE_8UINT,
                    0,
                    True,
                )
            else:
                rsgislib.imagecalc.imagePixelColumnSummary(
                    refLyrMskStackImg,
                    outMskImg,
                    rsgislib.imagecalc.StatsSummary(calcMedian=True),
                    "KEA",
                    rsgislib.TYPE_8UINT,
                    0,
                    True,
                )
            rsgislib.rastergis.pop_rat_img_stats(outMskImg, True, True, True)
            print("Created mask")

            idx = 1
            refLyrsLst = []
            print("create merged NDVI/NDWI layers")
            for img in inImagesSub2Ref:
                print("In Image (" + str(idx) + "):\t" + img)
                baseImgName = os.path.splitext(os.path.basename(img))[0]
                refLyrNDVIImg = os.path.join(
                    refLayersPath, "{}_ndvi.kea".format(baseImgName)
                )
                refLyrNDWIImg = os.path.join(
                    refLayersPath, "{}_ndwi.kea".format(baseImgName)
                )
                refLyrLclMskImg = os.path.join(
                    refLayersPath, "{}_waterLandMsk.kea".format(baseImgName)
                )

                nir_min, nir_max = rsgislib.imagecalc.get_img_band_min_max(
                    img, nBand, True, 0.0
                )

                nir_bright_img = os.path.join(
                    refLayersPath, "{}_nir_brightness.kea".format(baseImgName)
                )
                band_defns = [rsgislib.imagecalc.BandDefn("nir", img, nBand)]
                nir_range = nir_max - nir_min
                exp = "(nir==0)?0.0:(nir-{0})/{1}".format(nir_min, nir_range)
                rsgislib.imagecalc.band_math(
                    nir_bright_img, exp, "KEA", rsgislib.TYPE_32FLOAT, band_defns
                )

                reflyr_ndvi_scaled_img = os.path.join(
                    refLayersPath, "{}_ndvi_scaled.kea".format(baseImgName)
                )
                band_defns = [
                    rsgislib.imagecalc.BandDefn("ndvi", refLyrNDVIImg, 1),
                    rsgislib.imagecalc.BandDefn("bright", nir_bright_img, 1),
                ]
                exp = "(ndvi==-999)?-999:ndvi*bright"
                rsgislib.imagecalc.band_math(
                    reflyr_ndvi_scaled_img,
                    exp,
                    "KEA",
                    rsgislib.TYPE_32FLOAT,
                    band_defns,
                )

                refLyrImg = os.path.join(
                    refLayersPath, "{}_refHybrid.kea".format(baseImgName)
                )
                bandDefns = []
                bandDefns.append(
                    rsgislib.imagecalc.BandDefn("lmsk", refLyrLclMskImg, 1)
                )
                bandDefns.append(rsgislib.imagecalc.BandDefn("omsk", outMskImg, 1))
                bandDefns.append(
                    rsgislib.imagecalc.BandDefn("ndvi", reflyr_ndvi_scaled_img, 1)
                )
                bandDefns.append(rsgislib.imagecalc.BandDefn("ndwi", refLyrNDWIImg, 1))
                rsgislib.imagecalc.band_math(
                    refLyrImg,
                    "lmsk==0?-999:omsk==1?ndvi:omsk==2?ndwi:-999",
                    "KEA",
                    rsgislib.TYPE_32FLOAT,
                    bandDefns,
                )
                refLyrsLst.append(refLyrImg)
                idx = idx + 1

            print("Create reference image..")
            # Create REF Image
            rsgislib.imagecalc.get_img_idx_for_stat(
                refLyrsLst, outRefImg, "KEA", -999, rsgislib.SUMTYPE_MAX
            )
            if calcStats:
                # Pop Ref Image with stats
                rsgislib.rastergis.pop_rat_img_stats(outRefImg, True, True, True)

                # Open the clumps dataset as a gdal dataset
                ratDataset = osgeo.gdal.Open(outRefImg, osgeo.gdal.GA_Update)
                # Write colours to RAT
                rios.rat.writeColumn(ratDataset, "Red", red)
                rios.rat.writeColumn(ratDataset, "Green", green)
                rios.rat.writeColumn(ratDataset, "Blue", blue)
                rios.rat.writeColumn(ratDataset, "Alpha", alpha)
                rios.rat.writeColumn(ratDataset, "Image", imgLyrs)
                ratDataset = None

            # Create Composite Image
            rsgislib.imageutils.create_ref_img_composite_img(
                inImagesSub2Ref, outCompImg, outRefImg, gdalformat, dataType, 0.0
            )

            if calcStats:
                # Calc Stats
                rsgislib.imageutils.pop_img_stats(
                    outCompImg, use_no_data=True, no_data_val=0, calc_pyramids=True
                )

            if not refImgTmpPresent:
                shutil.rmtree(refLayersPath, ignore_errors=True)

            if not subsetImgTmpPresent:
                shutil.rmtree(subsetLayersPath, ignore_errors=True)

            if not reprojImgTmpPresent:
                shutil.rmtree(reprojLayersPath, ignore_errors=True)

            if not tmpPresent:
                shutil.rmtree(tmpPath, ignore_errors=True)
        else:
            raise rsgislib.RSGISPyException(
                "There were only {0} images which intersect with the reference image.".format(
                    nImgs
                )
            )

    elif len(inImages) == 1:
        print("Only 1 Input Image, Just Copying File to output")
        nBands = rsgislib.imageutils.get_img_band_count(inImages[0])
        if dataType is None:
            dataType = rsgislib.imageutils.get_rsgislib_datatype_from_img(inImages[0])
        rsgislib.imageutils.create_copy_img(
            refImg, outCompImg, nBands, 0, gdalformat, dataType
        )
        rsgislib.imageutils.includeImagesIndImgIntersect(outCompImg, [inImages[0]])
    else:
        raise rsgislib.RSGISPyException("List of input images was empty ")
