# -*- coding: utf-8 -*-
"""
/***************************************************************************
 MST
                                 A QGIS plugin
 This plugin creates minimum spanning trees in multiple ways.
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2019-11-06
        git sha              : $Format:%H$
        copyright            : (C) 2019 by Murat ÇALIŞKAN
        email                : caliskan.murat.20@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.                                   *
 *                                                                         *
 ***************************************************************************/
"""
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QFileDialog
from qgis.utils import iface
from qgis.core import Qgis
import math
from datetime import datetime

# Initialize Qt resources from file resources.py
from .resources import *
# Import the code for the dialog
from .minimum_spanning_trees_dialog import MSTDialog
import os.path
from osgeo import ogr, osr, gdal


class MST:
    """QGIS Plugin Implementation."""

    def __init__(self, iface):
#        self.dlg = MSTDialog()
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            self.plugin_dir,
            'i18n',
            'MST_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Minimum Spanning Tree')

        # Check if plugin was started the first time in current QGIS session
        # Must be set in initGui() to survive plugin reloads
        self.first_start = None       
        

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('MST', message)


    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            # Adds plugin icon to Plugins toolbar
            self.iface.addToolBarIcon(action)

        if add_to_menu:
            self.iface.addPluginToMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = ':/plugins/minimum_spanning_trees/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Minimum Spanning Tree'),
            callback=self.run,
            parent=self.iface.mainWindow())

        # will be set False in run()
        self.first_start = True


    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&Minimum Spanning Tree'),
                action)
            self.iface.removeToolBarIcon(action)

    def total_time(self, dt):
        tot_sec = dt.total_seconds()
        if tot_sec < 60:
            return "{} seconds.".format(str(int(tot_sec)))
        elif (tot_sec >= 60) and (tot_sec < 3600):
            sec = tot_sec%60
            mins = (tot_sec - sec) / 60.0
            return "{} minutes, {} seconds.".format(str(int(mins)), str(int(sec)))
        else:
            sec = tot_sec%60
            mins = ((tot_sec - sec) / 60) % 60
            hours = (((tot_sec - sec) / 60) - mins) / 60
            return "{} hours, {} minutes, {} seconds.".format(str(int(hours)), str(int(mins)), str(int(sec)))
    
    def select_m1_shp_input(self):
        self.dlg.m1_lineEdit_input.setText("")
        self.shpPath, self._filter = QFileDialog.getOpenFileName(self.dlg, "Select input file","", 'ESRI Shapefiles(*.shp *.SHP);; GeoJSON (*.GEOJSON *.geojson);; Geography Markup Language(*.GML)')
        try:
            self.shp = ogr.Open(self.shpPath)            
            self.layer = self.shp.GetLayer(0)
            self.name = self.layer.GetName()          
#            self.sr = self.layer.GetSpatialRef().ExportToProj4()
            
            self.dlg.m1_lbl_status.setText('<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>')
            self.dlg.m1_lineEdit_input.setText(self.shpPath)
            self.dlg.lbl_message_1.setText('<html><head/><body><p><span style=" color:#ff0000;"></span></p></body></html>')            
        except:
            self.dlg.m1_lbl_status.setText('<html><head/><body><p><span style=" color:#ff0000;"> X </span></p></body></html>')
            self.dlg.lbl_message_1.setText('<html><head/><body><p><span style=" color:#ff0000;"> Invalid input! </span></p></body></html>')
        
        if (self.dlg.m1_lbl_status.text() == '<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>') and (self.dlg.m3_lbl_status.text()=='<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>'):
            self.dlg.lbl_message_1.setText("")
                
    def select_m1_barrier_input(self):
        self.dlg.m1_lineEdit_input_2.setText("")
        self.shpBarrierPath, self._bfilter = QFileDialog.getOpenFileName(self.dlg, "Select barrier file","", 'ESRI Shapefiles(*.shp *.SHP);; GeoJSON (*.GEOJSON *.geojson);; Geography Markup Language(*.GML)')
        try:
            self.barrier = ogr.Open(self.shpBarrierPath)            
            self.blayer = self.barrier.GetLayer(0)
            self.bname = self.blayer.GetName()
            
            self.dlg.m1_lbl_status_2.setText('<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>')
            self.dlg.m1_lineEdit_input_2.setText(self.shpBarrierPath)
        except:
            self.dlg.m1_lbl_status_2.setText('<html><head/><body><p><span style=" color:#ff0000;"> X </span></p></body></html>')
                            
    def select_m1_shp_output(self):
        self.dlg.m1_lineEdit_output.setText("")
        self.shpPath, self._filter = QFileDialog.getSaveFileName(self.dlg, "Select input shp file", "", '*.shp')
        self.dlg.m1_lineEdit_output.setText(self.shpPath)
        
        
    def select_m2_shp_input(self):
        self.dlg.m2_lineEdit_input.setText("")
        self.dlg.cBox_costField.clear()
        self.shpPath, self._filter = QFileDialog.getOpenFileName(self.dlg, "Select input shp file","", 'ESRI Shapefiles(*.shp *.SHP);; GeoJSON (*.GEOJSON *.geojson);; Geography Markup Language(*.GML)')
        try:
            self.shp = ogr.Open(self.shpPath)
            self.layer = self.shp.GetLayer(0)
            self.name = self.layer.GetName()
#            self.sr = self.layer.GetSpatialRef().ExportToProj4()
            self.dlg.m2_lbl_status.setText('<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>')
            self.dlg.m2_lineEdit_input.setText(self.shpPath)
            self.dlg.lbl_message_2.setText('')
            self.dlg.cBox_costField.clear()
            self.layerDef = self.layer.GetLayerDefn()            
            self.fieldNames = [self.layerDef.GetFieldDefn(i).name for i in range(self.layerDef.GetFieldCount())] 
            self.dlg.cBox_costField.addItems(self.fieldNames)
        except:
            self.dlg.m2_lbl_status.setText('<html><head/><body><p><span style=" color:#ff0000;"> X </span></p></body></html>')
            self.dlg.lbl_message_2.setText('<html><head/><body><p><span style=" color:#ff0000;"> Invalid input! </span></p></body></html>')
    
    def select_m2_barrier_input(self):
        self.dlg.m2_lineEdit_input_2.setText("")
        self.shpBarrierPath, self._bfilter = QFileDialog.getOpenFileName(self.dlg, "Select barrier file","", 'ESRI Shapefiles(*.shp *.SHP);; GeoJSON (*.GEOJSON *.geojson);; Geography Markup Language(*.GML)')
        try:
            self.barrier = ogr.Open(self.shpBarrierPath)            
            self.blayer = self.barrier.GetLayer(0)
            self.bname = self.blayer.GetName()
            
            self.dlg.m2_lbl_status_2.setText('<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>')
            self.dlg.m2_lineEdit_input_2.setText(self.shpBarrierPath)
        except:
            self.dlg.m1_lbl_status_2.setText('<html><head/><body><p><span style=" color:#ff0000;"> X </span></p></body></html>')
            
    def select_m2_shp_output(self):
        self.dlg.m2_lineEdit_output.setText("")
        self.shpPath, self._filter = QFileDialog.getSaveFileName(self.dlg, "Select input shp file", "", '*.shp')
        self.dlg.m2_lineEdit_output.setText(self.shpPath)
        
        
    def select_m3_shp_input(self):            
        self.dlg.m3_lineEdit_input.setText("")
        self.shpPath, self._filter = QFileDialog.getOpenFileName(self.dlg, "Select input shp file","", 'ESRI Shapefiles(*.shp *.SHP);; GeoJSON (*.GEOJSON *.geojson);; Geography Markup Language(*.GML)')
        try:
            self.shp = ogr.Open(self.shpPath)
            self.layer = self.shp.GetLayer(0)
            self.name = self.layer.GetName()
#            self.sr = self.layer.GetSpatialRef().ExportToProj4()
            self.dlg.m3_lbl_status.setText('<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>')
            self.dlg.m3_lineEdit_input.setText(self.shpPath)
                
        except:
            self.dlg.m3_lbl_status.setText('<html><head/><body><p><span style=" color:#ff0000;"> X </span></p></body></html>')
            self.dlg.lbl_message_3.setText('<html><head/><body><p><span style=" color:#ff0000;"> Invalid input! </span></p></body></html>')
        
        if (self.dlg.m3_lbl_status2.text() == '<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>') and (self.dlg.m3_lbl_status.text()=='<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>'):
            self.dlg.lbl_message_3.setText("")
                
    def select_m3_raster_input(self):
        self.dlg.m3_lineEdit_input2.setText("")
        self.raster_path, self._filter = QFileDialog.getOpenFileName(self.dlg, "Select input raster file","")#, '*.shp')
        try:
            self.raster = gdal.Open(self.raster_path)
            self.xlt, self.a, self._, self.ylt, self.__, self.b = self.raster.GetGeoTransform()
            self.band = self.raster.GetRasterBand(1)
            self.ds_array = self.raster.ReadAsArray()
            
            self.dlg.m3_lbl_status2.setText('<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>')
            self.dlg.m3_lineEdit_input2.setText(self.raster_path)           
                
        except:
            self.dlg.m3_lbl_status2.setText('<html><head/><body><p><span style=" color:#ff0000;"> X </span></p></body></html>')
            self.dlg.lbl_message_3.setText('<html><head/><body><p><span style=" color:#ff0000;"> Invalid input! </span></p></body></html>')
           
        if (self.dlg.m3_lbl_status2.text() == '<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>') and (self.dlg.m3_lbl_status.text()=='<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>'):
            self.dlg.lbl_message_3.setText("")
    
    def select_m3_barrier_input(self):
        self.dlg.m3_lineEdit_input3.setText("")
        self.shpBarrierPath, self._bfilter = QFileDialog.getOpenFileName(self.dlg, "Select barrier file","", 'ESRI Shapefiles(*.shp *.SHP);; GeoJSON (*.GEOJSON *.geojson);; Geography Markup Language(*.GML)')
        try:
            self.barrier = ogr.Open(self.shpBarrierPath)            
            self.blayer = self.barrier.GetLayer(0)
            self.bname = self.blayer.GetName()
            
            self.dlg.m3_lbl_status3.setText('<html><head/><body><p><span style=" color:#00ff00;"> ✔ </span></p></body></html>')
            self.dlg.m3_lineEdit_input3.setText(self.shpBarrierPath)
        except:
            self.dlg.m3_lbl_status3.setText('<html><head/><body><p><span style=" color:#ff0000;"> X </span></p></body></html>')
                
    def select_m3_shp_output(self):
        self.dlg.m3_lineEdit_output.setText("")
        self.shpPath, self._filter = QFileDialog.getSaveFileName(self.dlg, "Select input shp file", "", '*.shp')
        self.dlg.m3_lineEdit_output.setText(self.shpPath)
    
    def getNeighbors_1(self, edges, barrier):
        if barrier==False:
            neighbors = []
            for i in edges:
                g1, g2 = i.GetPoint_2D(0), i.GetPoint_2D(i.GetPointCount()-1)
                p1, p2 = "POINT ({} {})".format(g1[0],g1[1]), "POINT ({} {})".format(g2[0],g2[1])
                dist = i.Length()
                neighbors.append((p1, p2, dist, i))
            neighbors = sorted(neighbors, key=lambda x:x[2])
        else:
            neighbors = []
            for i in edges:
                if not i.Intersects(barrier):
                    g1, g2 = i.GetPoint_2D(0), i.GetPoint_2D(i.GetPointCount()-1)
                    p1, p2 = "POINT ({} {})".format(g1[0],g1[1]), "POINT ({} {})".format(g2[0],g2[1])
                    dist = i.Length()        
                    neighbors.append((p1, p2, dist, i))
            neighbors = sorted(neighbors, key=lambda x:x[2])        
        return neighbors
    
    def getNeighbors_2(self, edges, costFields, barrier):
        if barrier==False:        
            neighbors = []
            for e,i in enumerate(edges):
                g1, g2 = i.GetPoint_2D(0), i.GetPoint_2D(i.GetPointCount()-1)
                p1, p2 = "POINT ({} {})".format(g1[0],g1[1]), "POINT ({} {})".format(g2[0],g2[1])
                cost = costFields[e]
                neighbors.append((p1, p2, cost, i))
            neighbors = sorted(neighbors, key=lambda x:x[2])
        else:        
            neighbors = []
            for e,i in enumerate(edges):
                if not i.Intersects(barrier):
                    g1, g2 = i.GetPoint_2D(0), i.GetPoint_2D(i.GetPointCount()-1)
                    p1, p2 = "POINT ({} {})".format(g1[0],g1[1]), "POINT ({} {})".format(g2[0],g2[1])
                    cost = costFields[e]
                    neighbors.append((p1, p2, cost, i))
            neighbors = sorted(neighbors, key=lambda x:x[2])            
        return neighbors
    
    def getVal(self, x, y, xlt, ylt, ds_array, band, a, b):
        px = (x - xlt) / a
        py = (y - ylt) / b
        band.GetStatistics(True, True)
        if (px < 0) or (py < 0):
            return None
        else:
            r, c = int(py), int(px)
            res = ds_array[r,c]
            if (res < band.GetMinimum()) or (res>band.GetMaximum()):
                return None
            else:
                return res
    
    def getCost(self, g, xlt, ylt, ds_array, band, a, b):
        total = 0    
        for i in range(len(g.GetPoints())-1):
            g1,g2 = g.GetPoints()[i], g.GetPoints()[i+1]
            g1X, g1Y = g1
            g2X, g2Y = g2
            
            dx, dy = g2X - g1X, g2Y - g1Y
            x, y = g1X, g1Y
            cost = float(self.getVal(g1X, g1Y, xlt, ylt, ds_array, band, a, b))            
            
            say = 2
            if dx == 0:
                while (y+a) < g2Y:
                    y += a
                    cost += self.getVal(x, y, xlt, ylt, ds_array, band, a, b)
                    say += 1
                cost += self.getVal(g2X, g2Y, xlt, ylt, ds_array, band, a, b)
                total += cost
                
            elif dy == 0:
                while (x+a) < g2X:
                    x += a
                    cost += self.getVal(x, y, xlt, ylt, ds_array, band, a, b)
                    say += 1
                cost += self.getVal(g2X,g2Y, xlt, ylt, ds_array, band, a, b)
                total += cost
            
            else:
                alpha = math.atan(dy/dx)
                d = a * math.cos(alpha)
                while (x+d) < g2X:
                    x += d
                    y = y + d * (dy/dx)
                    cost += self.getVal(x, y, xlt, ylt, ds_array, band, a, b)
                    say += 1
                cost += self.getVal(g2X, g2Y, xlt, ylt, ds_array, band, a, b)
                total += cost

        # sum of corresponding pixels
        if self.dlg.m3_radioButton_1.isChecked():
            result_cost = total

        # average of corresponding pixels  
        elif self.dlg.m3_radioButton_2.isChecked():
            result_cost = total/say

        # blending length and average
        elif self.dlg.m3_radioButton_3.isChecked():
            result_cost = (total/say) * g.Length()
            
        return result_cost
    
    
    def getNeighbors_3(self, edges, xlt, ylt, ds_array, band, a, b, barrier):
        if barrier == False:
            neighbors = []
            for e,i in enumerate(edges):
                g1, g2 = i.GetPoint_2D(0), i.GetPoint_2D(i.GetPointCount()-1)
                p1, p2 = "POINT ({} {})".format(g1[0],g1[1]), "POINT ({} {})".format(g2[0],g2[1])
                try:
                    cost = self.getCost(g=i, xlt=xlt, ylt=ylt, ds_array=ds_array, band=band, a=a, b=b)
                    neighbors.append((p1, p2, cost, i))
                except:
                    pass
            neighbors = sorted(neighbors, key=lambda x:x[2])
        else:
            neighbors = []
            for e,i in enumerate(edges):
                g1, g2 = i.GetPoint_2D(0), i.GetPoint_2D(i.GetPointCount()-1)
                p1, p2 = "POINT ({} {})".format(g1[0],g1[1]), "POINT ({} {})".format(g2[0],g2[1])
                if not i.Intersects(barrier):
                    try:
                        cost = self.getCost(g=i, xlt=xlt, ylt=ylt, ds_array=ds_array, band=band, a=a, b=b)
                        neighbors.append((p1, p2, cost, i))                    
                    except Exception as eee:
                        pass
#                        print(str(eee))        
            neighbors = sorted(neighbors, key=lambda x:x[2])
        return neighbors

    def execute(self, neighbors):
        gNumber = 2
        groups = {"g1":[[neighbors[0][0], neighbors[0][1]], [neighbors[0][3]], [neighbors[0][2]]]}
        
        for i in neighbors:
            c0, c1 = 0, 0
            g0, g1 = [], []
            for j in list(groups.items()):
                if i[0] in j[1][0] and i[1] in j[1][0]:
                    c0, c1 = -1, -1
                    break
                
                elif (i[0] in j[1][0]) or (i[1] in j[1][0]):
                    if (i[0] in j[1][0]) and (i[1] not in j[1][0]):
                        c1 += 1
                        groups[j[0]][0].append(i[1])
                        groups[j[0]][1].append(i[3])
                        groups[j[0]][2].append(i[2])
                        g0.append(j[0])
                        
                    if (i[1] in j[1][0]) and (i[0] not in j[1][0]):
                        c0 += 1
                        groups[j[0]][0].append(i[0])
                        groups[j[0]][1].append(i[3])
                        groups[j[0]][2].append(i[2])
                        g1.append(j[0])
            
            if (len(g0)>0) and (len(g1)>0):
                gName = "g" + str(gNumber)
                el1 = groups[g0[0]][0] + groups[g1[0]][0]
                el2 = groups[g0[0]][1] + groups[g1[0]][1]
                el3 = groups[g0[0]][2] + groups[g1[0]][2]
                
                groups[gName] = [el1, el2, el3]
                gNumber += 1
                del(groups[g0[0]])
                del(groups[g1[0]])
                    
            
            if (c0 == 0) and (c1 == 0):
                gName = "g" + str(gNumber)
                groups[gName] = [[i[0], i[1]], [i[3]], [i[2]]]
                gNumber += 1
        
        del g1
        gr = list(groups.values())
        mst, costs = [], []
        for i in gr:
            mst += i[1]
            costs += i[2]
                    
        for e1, g1 in enumerate(mst):
            for e2, g2 in enumerate(mst):    
                if e1 != e2:
                    if g1.Equals(g2):
                        del(costs[e2])
                        del(mst[e2])
                        
        return mst, costs
    
    
    def createShp(self, input_line, costs, out_shp, sr):
        driver = ogr.GetDriverByName('Esri Shapefile')
        ds = driver.CreateDataSource(out_shp)
        srs = osr.SpatialReference()
        srs.ImportFromProj4(sr)
        layer = ds.CreateLayer('mst', srs, ogr.wkbLineString)
        layer.CreateField(ogr.FieldDefn('id', ogr.OFTInteger))
        layer.CreateField(ogr.FieldDefn('cost', ogr.OFTReal))
        defn = layer.GetLayerDefn()
        
        for e,i in enumerate(zip(input_line, costs)):
            feat = ogr.Feature(defn)
            feat.SetField('id', e)
            feat.SetField('cost', i[1])
        
            # Geometry
            feat.SetGeometry(i[0])    
            layer.CreateFeature(feat)
        
        ds = layer = defn = feat = None
    
    def run(self):
        """Run method that performs all the real work"""
        # Create the dialog with elements (after translation) and keep reference
        # Only create GUI ONCE in callback, so that it will only load when the plugin is started
        if self.first_start == True:
#            self.first_start = False            
            self.dlg = MSTDialog()
            self.dlg.cBox_costField.clear()
            
            #Method 1
            self.dlg.m1_toolBtn_input.clicked.connect(self.select_m1_shp_input)
            self.dlg.m1_toolBtn_input_2.clicked.connect(self.select_m1_barrier_input)
            self.dlg.m1_toolBtn_output.clicked.connect(self.select_m1_shp_output)
            
            #Method 2
            self.dlg.m2_toolBtn_input.clicked.connect(self.select_m2_shp_input)
            self.dlg.m2_toolBtn_input_2.clicked.connect(self.select_m2_barrier_input)
            self.dlg.m2_toolBtn_output.clicked.connect(self.select_m2_shp_output)
            
            #Method 3
            self.dlg.m3_toolBtn_input.clicked.connect(self.select_m3_shp_input)
            self.dlg.m3_toolBtn_input2.clicked.connect(self.select_m3_raster_input)
            self.dlg.m3_toolBtn_input3.clicked.connect(self.select_m3_barrier_input)
            self.dlg.m3_toolBtn_output.clicked.connect(self.select_m3_shp_output)

        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            t1 = datetime.now()
            # Do something useful here - delete the line containing pass and
            # substitute with your code.                      
            #
            method = self.dlg.tabMethodMaster.currentIndex()

            # automatic cost
            if method == 1:                
                shp = ogr.Open(self.dlg.m1_lineEdit_input.text())
                layer = shp.GetLayer(0)
                name = layer.GetName()
                sr = layer.GetSpatialRef().ExportToProj4()
                query = """ SELECT * FROM "{}" """.format(name)
                
                try:
                    b_shp = ogr.Open(self.dlg.m1_lineEdit_input_2.text())
                    b_layer = b_shp.GetLayer(0)
                    b_name = b_layer.GetName()
                    b_query = """ SELECT * FROM "{}" """.format(b_name)                    
                
                    barrier_line = ogr.Geometry(ogr.wkbMultiLineString)
                    for b in b_shp.ExecuteSQL(b_query):
                        barrier_line.AddGeometry(b.GetGeometryRef())
                except:
                    barrier_line = False
                
                out_shp = self.dlg.m1_lineEdit_output.text()
                
                if layer.GetGeomType() == 3: #Polygon
                    pnt = ogr.Geometry(ogr.wkbMultiPoint)
                    for p in shp.ExecuteSQL(query):
                        pnt.AddGeometry(p.GetGeometryRef().Buffer(0).Centroid())
                    edges = pnt.DelaunayTriangulation(bOnlyEdges=True)
                    neighbors = self.getNeighbors_1(edges, barrier_line)
                        
                elif layer.GetGeomType() == 1: #Point
                    pnt = ogr.Geometry(ogr.wkbMultiPoint)
                    for p in shp.ExecuteSQL(query):
                        pnt.AddGeometry(p.GetGeometryRef())    
                    edges = pnt.DelaunayTriangulation(bOnlyEdges=True)   
                    neighbors = self.getNeighbors_1(edges, barrier_line)
            
                elif layer.GetGeomType() == 2: #Linestring
                    edges = ogr.Geometry(ogr.wkbMultiLineString)
                    for p in shp.ExecuteSQL(query):
                        edges.AddGeometry(p.GetGeometryRef())
                    neighbors = self.getNeighbors_1(edges, barrier_line)        

            # vector cost
            elif method == 0:
                shp = ogr.Open(self.dlg.m2_lineEdit_input.text())
                layer = shp.GetLayer(0)
                name = layer.GetName()
                sr = layer.GetSpatialRef().ExportToProj4()
                query = """ SELECT * FROM "{}" """.format(name)
                
                try:
                    b_shp = ogr.Open(self.dlg.m2_lineEdit_input_2.text())
                    b_layer = b_shp.GetLayer(0)
                    b_name = b_layer.GetName()
                    b_query = """ SELECT * FROM "{}" """.format(b_name)                    
                
                    barrier_line = ogr.Geometry(ogr.wkbMultiLineString)
                    for b in b_shp.ExecuteSQL(b_query):
                        barrier_line.AddGeometry(b.GetGeometryRef())
                except:
                    barrier_line = False
                
                out_shp = self.dlg.m2_lineEdit_output.text()
                
                edges = ogr.Geometry(ogr.wkbMultiLineString)
                costFields = []
                costFieldName = self.dlg.cBox_costField.currentText()
                for p in shp.ExecuteSQL(query):
                    geom = p.GetGeometryRef()
                    edges.AddGeometry(geom)                    
                    field = p.GetField(costFieldName)
                    costFields.append(field)            
                neighbors = self.getNeighbors_2(edges, costFields, barrier_line)

            # cost raster
            elif method == 2:
                raster_ = gdal.Open(self.dlg.m3_lineEdit_input2.text())
                xlt, a, _, ylt, d, b = raster_.GetGeoTransform()
                band = raster_.GetRasterBand(1)
                ds_array = raster_.ReadAsArray()
                
                shp = ogr.Open(self.dlg.m3_lineEdit_input.text())
                layer = shp.GetLayer(0)
                name = layer.GetName()
                sr = layer.GetSpatialRef().ExportToProj4()
                query = """ SELECT * FROM "{}" """.format(name)
                
                try:
                    b_shp = ogr.Open(self.dlg.m3_lineEdit_input3.text())
                    b_layer = b_shp.GetLayer(0)
                    b_name = b_layer.GetName()
                    b_query = """ SELECT * FROM "{}" """.format(b_name)                    
                
                    barrier_line = ogr.Geometry(ogr.wkbMultiLineString)
                    for bb in b_shp.ExecuteSQL(b_query):
                        barrier_line.AddGeometry(bb.GetGeometryRef())
                except:
                    barrier_line = False
                
                out_shp = self.dlg.m3_lineEdit_output.text()
            
                if layer.GetGeomType() == 3: #Polygon
                    pnt = ogr.Geometry(ogr.wkbMultiPoint)
                    for p in shp.ExecuteSQL(query):
                        pnt.AddGeometry(p.GetGeometryRef().Buffer(0).Centroid())
                    edges = pnt.DelaunayTriangulation(bOnlyEdges=True)
                    neighbors = self.getNeighbors_3(edges, xlt, ylt, ds_array, band, a, b, barrier=barrier_line)
                        
                elif layer.GetGeomType() == 1: #Point
                    pnt = ogr.Geometry(ogr.wkbMultiPoint)
                    for p in shp.ExecuteSQL(query):
                        pnt.AddGeometry(p.GetGeometryRef())    
                    edges = pnt.DelaunayTriangulation(bOnlyEdges=True)   
                    neighbors = self.getNeighbors_3(edges, xlt, ylt, ds_array, band, a, b, barrier=barrier_line)
            
                elif layer.GetGeomType() == 2: #Linestring
                    edges = ogr.Geometry(ogr.wkbMultiLineString)
                    for p in shp.ExecuteSQL(query):
                        edges.AddGeometry(p.GetGeometryRef())
                    neighbors = self.getNeighbors_3(edges, xlt, ylt, ds_array, band, a, b, barrier=barrier_line)
                           
            
            mst, costs = self.execute(neighbors)
            self.createShp(mst, costs, out_shp, sr)
            iface.addVectorLayer(out_shp, "", "ogr")
            t2 = datetime.now()
            dt = t2-t1
            iface.messageBar().pushMessage("Success", "MST Created! Total Cost:{},  Duration:{}".format(round(sum(costs)), self.total_time(dt)), level=Qgis.Success, duration=5)
