#!/usr/bin/env python
# -*- coding: utf-8 -*-
############################################################################
#
# PROGRAM:	grassr-clasif.py
# AUTHOR(S):	Francisco Gomariz-Castillo, Francisco Alonso-Sarría and 
#		        Fulgencio Cánovas-García
#
# PURPOSE:      To generate supervised clasifications using 
#               Maxlik, SMAP, RandomForest and Support Vector Machines.
#
#               It allows to combine different seature-sets although can be also 
#               used with just a group giving the value "" to the optional 
#               parameters. The allowed combination is:
#                 1. Three feature-sets. In this paper they include:
#                   a) Spectral
#                   b) Spectral and textural
#                   c) Spectral, textural and terrain derived
#                 2. Combination of images from different years     
#
#               Besides, it is posible to combine raster layers with different types
#               of information, for example set b might be a list of raster layers
#               representing climatic features and set c might be other type of 
#               information. 
# COPYRIGHT:    (C) 2013 by the GRASS Development Team
#
#               This program is free software under the GNU General Public
#               License (version 2). Read the file COPYING that comes with GRASS
#               for details.
#
#############################################################################
#%module
#% description: To generate supervised clasifications using Maxlik, SMAP, RandomForest and Support Vector Machines. It also allows to optimizer RF y SVM
#% keyword: classification
#% keyword: imagery
#% keyword: raster
#%end
#%option
#% key: spectral
#% type: string
#% description: List of spectral images
#% required: yes
#% multiple: no
#%end
#%option
#% key: training
#% type: string
#% description: Training raster
#% required: yes
#% multiple: no
#%end
#%option
#% key: validate
#% type: string
#% description: Validate raster
#% required: yes
#% multiple: no
#%end
#%option
#% key: textural
#% type: string
#% description: List of texture raster layers
#% required: no
#% multiple: no
#%end
#%option
#% key: covar
#% type: string
#% description: List of covariates (for example relief features)
#% required: no
#% multiple: no
#%end
#%option
#% key: seasons
#% type: string
#% description: Sufix refering to the season of the image
#% required: no
#% multiple: no
#%end
#%option
#% key: year
#% type: string
#% description: Year of the image
#% required: no
#% multiple: no
#%end
#%flag
#% key: c
#% description: Optimise RandomForest (mtry) and SVM (Cost) based on Reptead CV (k=5,n=10)
#%end

import sys
import os
import grass.script as gscript

def main():

   #variables definition
   spectral = options["spectral"]
   training = options["training"]
   validate = options["validate"]
   textural = options["textural"]
   covar = options["covar"]
   seasons = options["seasons"]
   year = options["year"]

#   spectral = sys.argv[1]
#   training = sys.argv[2]
#   validate = sys.argv[3]
#   optim = sys.argv[4]
#   textural = sys.argv[5]
#   covar = sys.argv[6]
#   seasons = sys.argv[7]
#   year = sys.argv[8]

   workdir = os.getcwd()

   #check platform and R
   from sys import platform
   if "R_HOME" in os.environ:
     if "win" in platform.lower():
       Rexec = os.environ['R_HOME'] + "/bin/Rscript.exe"
       Rexec = Rexec.replace('\\','/')
       Rexec = Rexec.replace('"','')
     if "linux" in platform.lower():
       Rexec = os.environ['R_HOME'] + "/bin/Rscript"
   else:
     gscript.fatal(_("R is not found. Check that R is installed and the environment variables are correctly set"))

   #check data----------------------------
#   if not training:
#     gscript.fatal(_("A raster layer with training areas should be introduced"))
#   if not validate:
#     gscript.fatal(_("A raster layer with validation areas should be introduced")) 
   if not textural:
     textural = ""
   if not covar:
     covar = "" 
   if not seasons:
     seasons = "" 
   if not year:
     year = "" 
   if flags['c']:
     optim = 1
   else:
     optim = 0

   datadisp = []
   if not spectral:
     datadisp.append("0")
   else:
     datadisp.append("S")     
   if textural == "":
     datadisp.append("0")
   else:
     datadisp.append("T")     
   if covar == "":
     datadisp.append("0")
   else:
     datadisp.append("R")

   seasons2 = seasons.replace(",","")

   #create array variables and raster names

   spectrala = spectral.split(',')
   texturala =  textural.split(',')
   covara = covar.split(',')
   seasona = seasons.split(',')

   #arrays----------------------------------------

   spectralN = []
   texturalN = []

   for y in range(0,len(spectrala)):
     for z in range(0,len(seasona)):
       spectralN.append(spectrala[y] + seasona[z])

   if textural != "":
     for y in range(0,len(texturala)):
      for z in range(0,len(seasona)):
        texturalN.append(texturala[y] + seasona[z])

   #normalise data---------------------------------

   for i in range(0,len(spectralN)):
     gscript.message(_("Normalise <%s> image...") % spectralN[i])
     stats = gscript.parse_command('r.univar', map=spectralN[i], flags='g')
     gscript.mapcalc("N$raster = int( 1000 * ( $raster - $mean ) / $stddev )", raster=spectralN[i], mean=stats['mean'],stddev=stats['stddev'],overwrite = True)
     spectralN[i] = "N" + spectralN[i]

   if textural != "":
     for i in range(0,len(texturalN)):
       gscript.message(_("Normalise <%s> image...") % texturalN[i])
       stats = gscript.parse_command('r.univar', map=texturalN[i], flags='g')
       gscript.mapcalc("N$raster = int( 1000 * ( $raster - $mean ) / $stddev )", raster=texturalN[i], mean=stats['mean'],stddev=stats['stddev'],overwrite = True)
       texturalN[i] = "N" + texturalN[i]

   if covar != "":
     for i in range(0,len(covara)):
      gscript.message(_("Normalise <%s> image...") % covara[i])
      stats = gscript.parse_command('r.univar', map=covara[i], flags='g')
      gscript.mapcalc("N$raster = int( 1000 * ( $raster - $mean ) / $stddev )", raster=covara[i], mean=stats['mean'],stddev=stats['stddev'],overwrite = True)
      covara[i] = "N" + covara[i]


   #MAXLIK AND SVM for classfication-------------------

   varimg = []
   varimg.append(','.join(map(str, spectralN)))
   if textural != "":
     varimg.append(','.join(map(str, spectralN + texturalN)))
   if covar != "":
      if textural != "":
        varimg.append(','.join(map(str, spectralN + texturalN + covara)))
      else:
        varimg.append(','.join(map(str, spectralN + covara)))
   else:
      varimg.append('0')

   for i in range(0,len(datadisp)):

     if datadisp[i] != "0":

       #define variable set, images and groups
       vari2 = datadisp[i]
       varimg2 = varimg[i]

       group = "image" + vari2
       gscript.parse_command('g.remove', type="group",name=group, flags='f')
       gscript.parse_command('i.group', group=group,subgroup=group,input=varimg2)

       #ML--------------------------------------
       typemodel='maxlik'
       sigfile= 'gensig_training' + vari2
       outclas='clasif_' + typemodel + vari2 + year + seasons2
       outreg='reg_' + typemodel + vari2 + year + seasons2
       gscript.parse_command('i.gensig', trainingmap=training,group=group,subgroup=group,signaturefile=sigfile,overwrite = True)
       gscript.parse_command('i.maxlik', group= group, subgroup=group, output=outclas, reject=outreg ,signaturefile = sigfile,overwrite = True)
       #kappa and confusion
       gscript.message(_("Calculating accuracy assessment for <%s> image...") % outclas)
       os.system('"%s" --vanilla %s/kappa-confusion.R %s %s %s %s %s %s %s' % (Rexec,workdir,vari2,year,validate,outclas,typemodel,workdir,seasons2) )

       #SMAP------------------------------------
       typemodel='smap'
       sigfile= 'gensigset_training' + vari2
       outclas='clasif_' + typemodel + vari2 + year + seasons2
       gscript.parse_command('i.gensigset', trainingmap=training,group=group,subgroup=group,sig=sigfile,overwrite = True)
       gscript.parse_command('i.smap', group= group, subgroup=group, output=outclas ,signaturefile = sigfile,overwrite = True)
       #kappa and confusion
       gscript.message(_("Calculating accuracy assessment for <%s> image...") % outclas)
       os.system('"%s" --vanilla %s/kappa-confusion.R %s %s %s %s %s %s %s ' % (Rexec,workdir,vari2,year,outclas,validate,typemodel,workdir,seasons2) )

       #RF AND SVM------------------------------------------------------------------
       os.system('"%s" --vanilla %s/clasifSVM-RF.R %s %s %s %s %s %s %s %s ' % (Rexec,workdir,vari2,year,varimg2,training,validate,optim,workdir,seasons2) )


   #finalise process
   os.system('rm %s/summaryCAL.Rdata' % (workdir) )
   os.system('rm %s/summaryVAL.Rdata' % (workdir) )

   gscript.parse_command('g.remove', type= 'rast', pattern='N*' , flags='f')

if __name__ == '__main__':
    options, flags = gscript.parser()
    main()
