# -*- coding: utf-8 -*-
"""
/***************************************************************************
 GWBuffRasterDialog
                                 A QGIS plugin
 Expands and interpolates edge values of Water Surface Elevation (WSE) rasters to produce groundwater (GW) buffer rasters
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                             -------------------
        begin                : 2022-08-31
        git sha              : $Format:%H$
        copyright            : (C) 2022 by Blair William Gerald Scriven
        email                : scrivenblair@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
"""

import os

from qgis.PyQt import uic
from qgis.PyQt import QtWidgets
from PyQt5.QtWidgets import QFileDialog
from qgis import processing
from qgis.core import QgsMapLayerProxyModel, QgsVectorLayer, QgsRasterLayer

# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'GW_Buffer_Raster_dialog_base.ui'))


class GWBuffRasterDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(GWBuffRasterDialog, self).__init__(parent)
        # Set up the user interface from Designer through FORM_CLASS.
        # After self.setupUi() you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)

        # Set appropriate function for each button when clicked 
        self.FindBuffFold_Button.clicked.connect(self.FindFolder_Buff_Button_clicked)
        self.Process_Button.clicked.connect(self.create_GW_Buffer)

        # Define the MapLayer_ComboBoxes 
        self.Vector_MapLayer_ComboBox.setFilters(QgsMapLayerProxyModel.VectorLayer)
        self.Vector_MapLayer_ComboBox.setCurrentIndex(-1) #clear the selection
        self.Raster_MapLayer_ComboBox.setFilters(QgsMapLayerProxyModel.RasterLayer) 
        self.Raster_MapLayer_ComboBox.setCurrentIndex(-1) #clear the selection

    def FindFolder_Buff_Button_clicked(self):
      # getExistingDirectory(self, label, default path to search for folder)
      foldname = QFileDialog.getExistingDirectory(self, "Open Directory")
      self.FindBuffFold_LineEdit.setText(str(foldname) + "/GWBuff.tif")

    def create_GW_Buffer(self):
      self.Pbar.setValue(0) # reset progress bar
      self.Error_Message_Label.setText("") # reset error message to blank

      # Set main function parameters
      VFileName = self.Vector_MapLayer_ComboBox.currentLayer()
      RFileName = self.Raster_MapLayer_ComboBox.currentLayer()
      BufferExtent = int(self.spinBox_ext.value())
      BuffFold = self.FindBuffFold_LineEdit.text()

      # Error Handling: Check for empty parameters
      if not BuffFold:
         self.Error_Message_Label.resize(400, 20) # You have to resize label everytime you change the text
         self.Error_Message_Label.setText("WARNING: You have not selected an output folder")
         return
      if type(RFileName) is not QgsRasterLayer:
         self.Error_Message_Label.resize(400, 20)
         self.Error_Message_Label.setText("WARNING: You have not selected a WSE raster file")
         return
      if type(VFileName) is not QgsVectorLayer:
         self.Error_Message_Label.resize(400, 20) 
         self.Error_Message_Label.setText("WARNING: You have not selected a WSE vector file")
         return

      # Create the GDAL Warp code to maintain raster extent and pixel resolution
      ex = RFileName.extent()
      xmax = int(ex.xMaximum()) + BufferExtent # Don't add or subtract BufferExtent for merged raster (when fixed)
      ymax = int(ex.yMaximum()) + BufferExtent
      xmin = int(ex.xMinimum()) - BufferExtent
      ymin = int(ex.yMinimum()) - BufferExtent
      pixelSizeX = RFileName.rasterUnitsPerPixelX()
      pixelSizeY = RFileName.rasterUnitsPerPixelY()
      PixExt = '-tr ' + str(pixelSizeX) + ' ' + str(pixelSizeY) +  ' -txe ' + str(xmin) + ' ' + str(xmax) + ' -tye ' + str(ymin) + ' ' + str(ymax)

      ### START THE PROCESSING CODE TO CREATE GW RASTER BUFFER ####################################

      fix_geom = processing.run("native:fixgeometries", {'INPUT':VFileName,
                                                         'OUTPUT': 'memory:'})
      self.Pbar.setValue(10)
      vertex_points = processing.run("native:extractvertices", {'INPUT':fix_geom['OUTPUT'],
                                                                'OUTPUT':'memory:'})
      self.Pbar.setValue(15)
      Sample_points = processing.run("native:rastersampling", { 'INPUT':vertex_points['OUTPUT'],
                                                                'RASTERCOPY':RFileName,
                                                                'COLUMN_PREFIX': 'SAMPLE_VAL',
                                                                'OUTPUT': 'memory:'})
      self.Pbar.setValue(20)
      extract_Sample_points = processing.run("qgis:extractbyexpression", { 'INPUT':Sample_points['OUTPUT'],
                                                                           'EXPRESSION':'SAMPLE_VAL1 is not NULL',
                                                                           'OUTPUT': 'memory:'})
      self.Pbar.setValue(25)
      first_Buff = processing.run("gdal:gridnearestneighbor", {'INPUT':extract_Sample_points['OUTPUT'],
                                                               'RADIUS_1':int(BufferExtent),
                                                               'RADIUS_2':int(BufferExtent),
                                                               'NODATA': -100,
                                                               'Z_FIELD':'SAMPLE_VAL1',
                                                               'EXTRA':PixExt,
                                                               'DATA_TYPE':5, # Float32
                                                               'OUTPUT':'TEMPORARY_OUTPUT'}) # Needed for temp rasters
      self.Pbar.setValue(60)
      Extent_poly = processing.run("native:extenttolayer", {'INPUT':first_Buff['OUTPUT'],
                                                            'OUTPUT':'memory:'})
      self.Pbar.setValue(65)
      Dif_poly = processing.run("qgis:difference", {'INPUT':Extent_poly['OUTPUT'],
                                                    'OVERLAY':fix_geom['OUTPUT'],
                                                    'OUTPUT': 'memory:'})
      self.Pbar.setValue(70)
      processing.runAndLoadResults("gdal:cliprasterbymasklayer", {'INPUT':first_Buff['OUTPUT'],
                                                                  'MASK':Dif_poly['OUTPUT'],
                                                                  'NODATA':-100,
                                                                  'ALPHA_BAND':False,
                                                                  'CROP_TO_CUTLINE':True,
                                                                  'KEEP_RESOLUTION':True,
                                                                  'SET_RESOLUTION':False,
                                                                  'MULTITHREADING':False,
                                                                  'DATA_TYPE':0,
                                                                  'OUTPUT':BuffFold})
      ### END OF PROCESSING CODE ##################################################################
      
      self.Pbar.setValue(100)