# -*- coding: utf-8 -*-

"""
/***************************************************************************
 CreateProject
                                 A QGIS plugin
 Process that able you to create a Graph for Graphab
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2020-07-02
        copyright            : (C) 2020 by ThéMA
        email                : robin.marlinl@gmail.com
        author               : Robin Marlin-Lefebvre
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program 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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

__author__ = 'robin.marlinl@gmail.com'
__date__ = '2020-07-02'
__copyright__ = '(C) 2020 by ThéMA'

# This will get replaced with a git SHA1 when you do a git archive

__revision__ = '$Format:%H$'

from qgis._core import QgsProcessingParameterBoolean
from qgis.core import (QgsProcessingParameterString,
                       QgsProcessingParameterFolderDestination,
                       QgsProcessingParameterNumber,
                       QgsProcessingParameterRasterLayer, QgsProcessingParameterDefinition)

import os
import tempfile
from osgeo import gdal

from .GraphabAlgoProcessing import GraphabAlgoProcessing


class CreateProject(GraphabAlgoProcessing):
    """
    Processing algorithm use to create a new Project. It inherit of GraphabAlgoProcessing
    that execute the command send by this class and it inherit of QgsProcessingAlgorithm
    """
    
    def __init__(self, plugin):
        super().__init__(plugin)

    # Constants used to refer to parameters and outputs. They will be
    # used when calling the algorithm from another algorithm, or when
    # calling from the QGIS console.

    INPUT = 'INPUT'
    NAMEPROJECT = 'NAMEPROJECT'
    LANDCODE = 'LANDCODE'
    DIRPATH = 'DIRPATH'
    SIZEPATCHES = 'SIZEPATCHES'
    NODATA = 'NODATA'
    CON8 = 'CON8'
    MAXSIZE = 'MAXSIZE'

    def initAlgorithm(self, config):
        """
        Here we define the inputs and output of the algorithm, along
        with some other properties.
        """

        # Input for the Graph name
        self.addParameter(
            QgsProcessingParameterString(
                self.NAMEPROJECT,
                self.translate('py', 'Project name'),
                defaultValue='Project1',
                optional=False
            )
        )
        
        # Input for the file that represent the Graphab Project
        self.addParameter(
            QgsProcessingParameterRasterLayer(
                self.INPUT,
                self.translate('py', 'Landscape raster'),
                optional=False
            )
        )
        
        # Input for the land code
        self.addParameter(
            QgsProcessingParameterString(
                self.LANDCODE,
                self.translate('py', 'Habitat patch codes (separated by commas ex: 1,4,3)'),
                optional=False
            )
        )
        
        # Folder destination
        self.addParameter(
            QgsProcessingParameterFolderDestination(
                self.DIRPATH,
                self.translate('py', 'Project destination folder'),
                optional=False
            )
        )
        
        # Size minPatches
        self.addParameter(
            QgsProcessingParameterNumber(
                self.SIZEPATCHES,
                self.translate('py', 'Minimum size patches (hectare)'),
                type=QgsProcessingParameterNumber.Double,
                minValue=0.0,
                defaultValue=0.0,
                optional=False
            )
        )

        # Nodata
        self.addParameter(
            QgsProcessingParameterNumber(
                self.NODATA,
                self.translate('py', 'Nodata'),
                type=QgsProcessingParameterNumber.Double,
                defaultValue=None,
                optional=True
            )
        )

        # Max size
        param = QgsProcessingParameterNumber(
                self.MAXSIZE,
                self.translate('py', 'Maximum size of patches in meter'),
                type=QgsProcessingParameterNumber.Double,
                minValue=0.0,
                defaultValue=0.0,
                optional=False
            )
        param.setFlags(param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(param)

        # 8 Connexity
        param = QgsProcessingParameterBoolean(
            self.CON8,
            self.translate('py', '8 connexity for patch definition'),
            defaultValue=False,
            optional=False
        )
        param.setFlags(param.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
        self.addParameter(param)

    def processAlgorithm(self, parameters, context, feedback):
        """
        Create a command line depending of parameters set by the user and send it to its parent 
        to execute it
        """
        # Get all parameter set
        raster = self.parameterDefinition('INPUT').valueAsPythonString(parameters['INPUT'], context)
        projectName = self.parameterAsString(parameters, self.NAMEPROJECT, context)
        landCodes = self.parameterAsString(parameters, self.LANDCODE, context)
        dirPath = self.parameterAsFile(parameters, self.DIRPATH, context)
        sizePatches = self.parameterAsDouble(parameters, self.SIZEPATCHES, context)
        nodata = self.parameterAsString(parameters, self.NODATA, context)
        con8 = self.parameterAsBool(parameters, self.CON8, context)
        maxsize = self.parameterAsDouble(parameters, self.MAXSIZE, context)

        raster = raster[1:-1]
        
        pathRaster = os.path.normcase(r''+raster)
        dirPath = os.path.normcase(r''+dirPath)
        self.projectFile = os.path.join(dirPath, projectName, projectName + ".xml")

        filename, file_extension = os.path.splitext(pathRaster)
        
        _output = None
        if file_extension != '.tif':
            #open the a temporary output file in write and read mode
            _output = tempfile.NamedTemporaryFile(mode = 'wb+', dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'temp'), prefix = 'temp', suffix = '.tif', delete = False)
            #close the file
            _output.close()
            
            # export the raster file in a tif file
            ds = gdal.Open(pathRaster)
            gdal.Translate(_output.name, ds)
                
            # get the new path for the temp file
            pathRaster = os.path.normcase(_output.name)
        
        #create the command that will be execute
        commandToExec = ['--create', projectName, pathRaster, 'habitat='+landCodes, 'dir='+dirPath, 'minarea='+str(sizePatches)]

        if nodata != '':
            commandToExec.append('nodata=' + nodata)

        if con8:
            commandToExec.append('con8')

        if maxsize > 0:
            commandToExec.append('maxsize=' + str(maxsize))

        #execute the command
        super().processAlgorithm(commandToExec, context, feedback)
        
        if _output is not None:
            # remove temporary file
            os.remove(_output.name)
        
        return {}

    def postProcessAlgorithm(self, context, feedback):
        """After the execution of the processing, this function
        add and show the new Graph in the map. """
        if not self.executionError:
            self.plugin.loadProject(self.projectFile)

        return {}

    def name(self):
        """
        Returns the algorithm name, used for identifying the algorithm. This
        string should be fixed for the algorithm, and must not be localised.
        The name should be unique within each provider. Names should contain
        lowercase alphanumeric characters only and no spaces or other
        formatting characters.
        """
        return 'create_project'

    def displayName(self):
        """
        Returns the translated algorithm name, which should be used for any
        user-visible display of the algorithm name.
        """
        return self.translate('py', 'Create Project')


    def createInstance(self):
        return CreateProject(self.plugin)
