class DockWidgetQueries(QgsDockWidget, DOCKWIDGET_UI):

    zoom_to_features_requested = pyqtSignal(QgsVectorLayer, list, dict,
                                            int)  # layer, ids, t_ids, duration

    def __init__(self, iface, db, qgis_utils, ladm_data, parent=None):
        super(DockWidgetQueries, self).__init__(None)
        self.setupUi(self)
        self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.iface = iface
        self._db = db
        self.qgis_utils = qgis_utils
        self.ladm_data = ladm_data
        self.logger = Logger()
        self.canvas = iface.mapCanvas()
        self.active_map_tool_before_custom = None
        self.names = self._db.names

        self.clipboard = QApplication.clipboard()

        # Required layers
        self.restart_dict_of_layers()

        self._identify_tool = None

        self.add_layers()
        self.fill_combos()

        self.btn_identify_plot.setIcon(
            QIcon(":/Asistente-LADM_COL/resources/images/spatial_unit.png"))

        # Set connections
        self.btn_alphanumeric_query.clicked.connect(self.alphanumeric_query)
        self.cbo_parcel_fields.currentIndexChanged.connect(
            self.search_field_updated)
        self.btn_identify_plot.clicked.connect(self.btn_plot_toggled)

        # Context menu
        self._set_context_menus()

        # Create maptool
        self.maptool_identify = QgsMapToolIdentifyFeature(self.canvas)

        self.initialize_field_values_line_edit()

    def search_field_updated(self, index=None):
        self.initialize_field_values_line_edit()

    def initialize_field_values_line_edit(self):
        self.txt_alphanumeric_query.setLayer(
            self._layers[self.names.OP_PARCEL_T][LAYER])
        idx = self._layers[self.names.OP_PARCEL_T][LAYER].fields().indexOf(
            self.cbo_parcel_fields.currentData())
        self.txt_alphanumeric_query.setAttributeIndex(idx)

    def _set_context_menus(self):
        self.tree_view_basic.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree_view_basic.customContextMenuRequested.connect(
            self.show_context_menu)

        self.tree_view_legal.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree_view_legal.customContextMenuRequested.connect(
            self.show_context_menu)

        self.tree_view_property_record_card.setContextMenuPolicy(
            Qt.CustomContextMenu)
        self.tree_view_property_record_card.customContextMenuRequested.connect(
            self.show_context_menu)

        self.tree_view_physical.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree_view_physical.customContextMenuRequested.connect(
            self.show_context_menu)

        self.tree_view_economic.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tree_view_economic.customContextMenuRequested.connect(
            self.show_context_menu)

    def restart_dict_of_layers(self):
        self._layers = {
            self.names.OP_PLOT_T: {
                'name': self.names.OP_PLOT_T,
                'geometry': QgsWkbTypes.PolygonGeometry,
                LAYER: None
            },
            self.names.OP_PARCEL_T: {
                'name': self.names.OP_PARCEL_T,
                'geometry': None,
                LAYER: None
            },
            self.names.COL_UE_BAUNIT_T: {
                'name': self.names.COL_UE_BAUNIT_T,
                'geometry': None,
                LAYER: None
            }
        }

    def add_layers(self):
        self.qgis_utils.get_layers(self._db, self._layers, load=True)
        if not self._layers:
            self.restart_dict_of_layers()  # Let it ready for the next call
            return None

        # Layer was found, listen to its removal so that we can deactivate the custom tool when that occurs
        try:
            self._layers[self.names.OP_PLOT_T][LAYER].willBeDeleted.disconnect(
                self.layer_removed)
        except TypeError as e:
            pass
        self._layers[self.names.OP_PLOT_T][LAYER].willBeDeleted.connect(
            self.layer_removed)

        # Layer was found, listen to its removal so that we can update the variable properly
        try:
            self._layers[
                self.names.OP_PARCEL_T][LAYER].willBeDeleted.disconnect(
                    self.parcel_layer_removed)
        except TypeError as e:
            pass
        self._layers[self.names.OP_PARCEL_T][LAYER].willBeDeleted.connect(
            self.parcel_layer_removed)

        # Layer was found, listen to its removal so that we can update the variable properly
        try:
            self._layers[
                self.names.COL_UE_BAUNIT_T][LAYER].willBeDeleted.disconnect(
                    self.uebaunit_table_removed)
        except TypeError as e:
            pass
        self._layers[self.names.COL_UE_BAUNIT_T][LAYER].willBeDeleted.connect(
            self.uebaunit_table_removed)

    def initialize_tool(self):
        self._layers[self.names.OP_PLOT_T][LAYER] = None
        self.initialize_tools(new_tool=None, old_tool=self.maptool_identify)
        self.btn_plot_toggled()

    def update_db_connection(self, db, ladm_col_db, db_source):
        self._db = db
        self.initialize_tool()

        if not ladm_col_db:
            self.setVisible(False)

    def layer_removed(self):
        # The required layer was removed, deactivate custom tool
        self.initialize_tool()

    def parcel_layer_removed(self):
        self._layers[self.names.OP_PARCEL_T][LAYER] = None

    def uebaunit_table_removed(self):
        self._layers[self.names.COL_UE_BAUNIT_T][LAYER] = None

    def fill_combos(self):
        self.cbo_parcel_fields.clear()

        self.cbo_parcel_fields.addItem(
            QCoreApplication.translate("DockWidgetQueries", "Parcel Number"),
            self.names.OP_PARCEL_T_PARCEL_NUMBER_F)
        self.cbo_parcel_fields.addItem(
            QCoreApplication.translate("DockWidgetQueries",
                                       "Previous Parcel Number"),
            self.names.OP_PARCEL_T_PREVIOUS_PARCEL_NUMBER_F)
        self.cbo_parcel_fields.addItem(
            QCoreApplication.translate("DockWidgetQueries",
                                       "Folio de Matrícula Inmobiliaria"),
            self.names.OP_PARCEL_T_FMI_F)

    def initialize_tools(self, new_tool, old_tool):
        if self.maptool_identify == old_tool:
            # custom identify was deactivated
            try:
                self.canvas.mapToolSet.disconnect(self.initialize_tools)
            except TypeError as e:
                pass
            self.btn_identify_plot.setChecked(False)
        else:
            # custom identify was activated
            pass

    def btn_plot_toggled(self):
        if self.btn_identify_plot.isChecked():
            self.prepare_identify_plot()
        else:
            # The button was toggled and deactivated, go back to the previous tool
            self.canvas.setMapTool(self.active_map_tool_before_custom)

    def prepare_identify_plot(self):
        """
            Custom Identify tool was activated, prepare everything for identifying plots
        """
        self.active_map_tool_before_custom = self.canvas.mapTool()

        self.btn_identify_plot.setChecked(True)

        self.canvas.mapToolSet.connect(self.initialize_tools)

        if self._layers[self.names.OP_PLOT_T][LAYER] is None:
            self.add_layers()

        self.maptool_identify.setLayer(
            self._layers[self.names.OP_PLOT_T][LAYER])
        cursor = QCursor()
        cursor.setShape(Qt.PointingHandCursor)
        self.maptool_identify.setCursor(cursor)
        self.canvas.setMapTool(self.maptool_identify)

        try:
            self.maptool_identify.featureIdentified.disconnect()
        except TypeError as e:
            pass
        self.maptool_identify.featureIdentified.connect(self.get_info_by_plot)

    def get_info_by_plot(self, plot_feature):
        plot_t_id = plot_feature[self.names.T_ID_F]
        self.canvas.flashFeatureIds(self._layers[self.names.OP_PLOT_T][LAYER],
                                    [plot_feature.id()],
                                    QColor(255, 0, 0, 255),
                                    QColor(255, 0, 0, 0),
                                    flashes=1,
                                    duration=500)

        with OverrideCursor(Qt.WaitCursor):
            if not self.isVisible():
                self.show()

            self.search_data_by_component(plot_t_id=plot_t_id,
                                          zoom_and_select=False)
            self._layers[self.names.OP_PLOT_T][LAYER].selectByIds(
                [plot_feature.id()])

    def search_data_by_component(self, **kwargs):
        self._layers[self.names.OP_PLOT_T][LAYER].removeSelection()

        # Read zoom_and_select parameter and remove it from kwargs
        bZoom = False
        if 'zoom_and_select' in kwargs:
            bZoom = kwargs['zoom_and_select']
            del kwargs['zoom_and_select']

        records = self._db.get_igac_basic_info(**kwargs)
        self.setup_tree_view(self.tree_view_basic, records)

        if bZoom:
            # Zoom to resulting plots
            plot_t_ids = self.get_plot_t_ids_from_basic_info(records)
            if plot_t_ids:
                features = self.ladm_data.get_features_from_t_ids(
                    self._layers[self.names.OP_PLOT_T][LAYER],
                    self.names.T_ID_F, plot_t_ids, True, True)
                plot_ids = [feature.id() for feature in features]
                self.zoom_to_features_requested.emit(
                    self._layers[self.names.OP_PLOT_T][LAYER], plot_ids,
                    dict(), 500)
                self._layers[self.names.OP_PLOT_T][LAYER].selectByIds(plot_ids)

        records = self._db.get_igac_legal_info(**kwargs)
        self.setup_tree_view(self.tree_view_legal, records)

        records = self._db.get_igac_property_record_card_info(**kwargs)
        self.setup_tree_view(self.tree_view_property_record_card, records)

        records = self._db.get_igac_physical_info(**kwargs)
        self.setup_tree_view(self.tree_view_physical, records)

        records = self._db.get_igac_economic_info(**kwargs)
        self.setup_tree_view(self.tree_view_economic, records)

    def setup_tree_view(self, tree_view, records):
        """
        Configure result tree views

        :param tree_view:
        :return:
        """
        tree_view.setModel(TreeModel(self.names, data=records))
        tree_view.expandAll()
        self.add_thumbnails_to_tree_view(tree_view)

    def add_thumbnails_to_tree_view(self, tree_view):
        """
        Gets a list of model indexes corresponding to extFiles objects to show a preview

        :param model:
        :return:
        """
        model = tree_view.model()
        indexes = model.getPixmapIndexList()
        for idx in indexes:
            url = model.data(idx, Qt.UserRole)['url']
            res, image = self.download_image("{}{}".format(
                url, SUFFIX_GET_THUMBNAIL))
            if res:
                pixmap = QPixmap()
                pixmap.loadFromData(image)
                label = QLabel()
                label.setPixmap(pixmap)
                tree_view.setIndexWidget(idx, label)

    def get_plot_t_ids_from_basic_info(self, records):
        res = []
        if records:
            for record in records:
                if self.names.OP_PLOT_T in record:
                    for element in record[self.names.OP_PLOT_T]:
                        res.append(element['id'])

        return res

    def alphanumeric_query(self):
        """
        Alphanumeric query
        """
        option = self.cbo_parcel_fields.currentData()
        query = self.txt_alphanumeric_query.value()
        if query:
            if option == self.names.OP_PARCEL_T_FMI_F:
                self.search_data_by_component(parcel_fmi=query,
                                              zoom_and_select=True)
            elif option == self.names.OP_PARCEL_T_PARCEL_NUMBER_F:
                self.search_data_by_component(parcel_number=query,
                                              zoom_and_select=True)
            else:  # previous_parcel_number
                self.search_data_by_component(previous_parcel_number=query,
                                              zoom_and_select=True)
        else:
            self.iface.messageBar().pushMessage(
                "Asistente LADM_COL",
                QCoreApplication.translate("DockWidgetQueries",
                                           "First enter a query"))

    def show_context_menu(self, point):
        tree_view = self.sender()
        index = tree_view.indexAt(point)

        context_menu = QMenu("Context menu")

        index_data = index.data(Qt.UserRole)

        if index_data is None:
            return

        if "value" in index_data:
            action_copy = QAction(
                QCoreApplication.translate("DockWidgetQueries", "Copy value"))
            action_copy.triggered.connect(
                partial(self.copy_value, index_data["value"]))
            context_menu.addAction(action_copy)
            context_menu.addSeparator()

        if "url" in index_data:
            action_open_url = QAction(
                QCoreApplication.translate("DockWidgetQueries", "Open URL"))
            action_open_url.triggered.connect(
                partial(self.open_url, index_data["url"]))
            context_menu.addAction(action_open_url)
            context_menu.addSeparator()

        # Configure actions for tables/layers
        if "type" in index_data and "id" in index_data:
            table_name = index_data["type"]
            table_package = LayerConfig.get_dict_table_package(self.names)
            t_id = index_data["id"]
            geometry_type = None
            if table_name in table_package and table_package[
                    table_name] == LADMNames.SPATIAL_UNIT_PACKAGE:
                # Layers in Spatial Unit package have double geometry, we need the polygon one
                geometry_type = QgsWkbTypes.PolygonGeometry

            if table_name == self.names.OP_PARCEL_T:
                if self._layers[
                        self.names.OP_PARCEL_T][LAYER] is None or self._layers[
                            self.names.
                            OP_PLOT_T][LAYER] is None or self._layers[
                                self.names.COL_UE_BAUNIT_T][LAYER] is None:
                    self.add_layers()
                layer = self._layers[self.names.OP_PARCEL_T][LAYER]
                self.iface.layerTreeView().setCurrentLayer(layer)
            else:
                layer = self.qgis_utils.get_layer(self._db, table_name,
                                                  geometry_type, True)

            if layer is not None:
                if layer.isSpatial():
                    action_zoom_to_feature = QAction(
                        QCoreApplication.translate(
                            "DockWidgetQueries",
                            "Zoom to {} with {}={}").format(
                                table_name, self.names.T_ID_F, t_id))
                    action_zoom_to_feature.triggered.connect(
                        partial(self.zoom_to_feature, layer, t_id))
                    context_menu.addAction(action_zoom_to_feature)

                if table_name == self.names.OP_PARCEL_T:
                    # We show a handy option to zoom to related plots
                    plot_ids = self.ladm_data.get_plots_related_to_parcels(
                        self._db, [t_id], None,
                        self._layers[self.names.OP_PLOT_T][LAYER],
                        self._layers[self.names.COL_UE_BAUNIT_T][LAYER])
                    if plot_ids:
                        action_zoom_to_plots = QAction(
                            QCoreApplication.translate(
                                "DockWidgetQueries",
                                "Zoom to related plot(s)"))
                        action_zoom_to_plots.triggered.connect(
                            partial(self.zoom_to_plots, plot_ids))
                        context_menu.addAction(action_zoom_to_plots)

                action_open_feature_form = QAction(
                    QCoreApplication.translate(
                        "DockWidgetQueries",
                        "Open form for {} with {}={}").format(
                            table_name, self.names.T_ID_F, t_id))
                action_open_feature_form.triggered.connect(
                    partial(self.open_feature_form, layer, t_id))
                context_menu.addAction(action_open_feature_form)

        if context_menu.actions():
            context_menu.exec_(tree_view.mapToGlobal(point))

    def copy_value(self, value):
        self.clipboard.setText(str(value))

    def open_url(self, url):
        webbrowser.open(url)

    def zoom_to_feature(self, layer, t_id):
        feature = self.get_feature_from_t_id(layer, t_id)
        self.iface.mapCanvas().zoomToFeatureIds(layer, [feature.id()])
        self.canvas.flashFeatureIds(layer, [feature.id()],
                                    QColor(255, 0, 0, 255),
                                    QColor(255, 0, 0, 0),
                                    flashes=1,
                                    duration=500)

    def open_feature_form(self, layer, t_id):
        feature = self.get_feature_from_t_id(layer, t_id)
        self.iface.openFeatureForm(layer, feature)

    def get_feature_from_t_id(self, layer, t_id):
        field_idx = layer.fields().indexFromName(self.names.T_ID_F)
        request = QgsFeatureRequest(
            QgsExpression("{}={}".format(self.names.T_ID_F, t_id)))
        request.setFlags(QgsFeatureRequest.NoGeometry)

        iterator = layer.getFeatures(request)
        feature = QgsFeature()
        res = iterator.nextFeature(feature)
        if res:
            return feature

        return None

    def zoom_to_plots(self, plot_ids):
        self.iface.mapCanvas().zoomToFeatureIds(
            self._layers[self.names.OP_PLOT_T][LAYER], plot_ids)
        self.canvas.flashFeatureIds(self._layers[self.names.OP_PLOT_T][LAYER],
                                    plot_ids,
                                    QColor(255, 0, 0, 255),
                                    QColor(255, 0, 0, 0),
                                    flashes=1,
                                    duration=500)

    def closeEvent(self, event):
        try:
            self.canvas.mapToolSet.disconnect(self.initialize_tools)
        except TypeError as e:
            pass
        self.canvas.setMapTool(self.active_map_tool_before_custom)

    def download_image(self, url):
        res = False
        img = None
        msg = {'text': '', 'level': Qgis.Warning}
        if url:
            self.logger.info(__name__, "Downloading file from {}".format(url))
            msg = "Downloading image from document repository (this might take a while)..."
            with ProcessWithStatus(msg):
                if self.qgis_utils.is_connected(TEST_SERVER):

                    nam = QNetworkAccessManager()
                    request = QNetworkRequest(QUrl(url))
                    reply = nam.get(request)

                    loop = QEventLoop()
                    reply.finished.connect(loop.quit)
                    loop.exec_()

                    status = reply.attribute(
                        QNetworkRequest.HttpStatusCodeAttribute)
                    if status == 200:
                        res = True
                        img = reply.readAll()
                    else:
                        res = False
                        msg['text'] = QCoreApplication.translate(
                            "SettingsDialog",
                            "There was a problem connecting to the server. The server might be down or the service cannot be reached at the given URL."
                        )
                else:
                    res = False
                    msg['text'] = QCoreApplication.translate(
                        "SettingsDialog",
                        "There was a problem connecting to Internet.")

        else:
            res = False
            msg['text'] = QCoreApplication.translate("SettingsDialog",
                                                     "Not valid URL")

        if not res:
            self.logger.log_message(__name__, msg['text'], msg['level'])
        return (res, img)
class LADMQueryController(QObject):

    close_view_requested = pyqtSignal()
    zoom_to_features_requested = pyqtSignal(QgsVectorLayer, list,
                                            dict)  # layer, ids, t_ids

    def __init__(self, db, ladm_data):
        QObject.__init__(self)

        self._db = db
        self._ladm_data = ladm_data

        self.logger = Logger()
        self.app = AppInterface()
        self.clipboard = QApplication.clipboard()
        self._layers = dict()
        self._ladm_queries = ConfigDBsSupported().get_db_factory(
            self._db.engine).get_ladm_queries()

        self._restart_dict_of_layers()
        self._add_layers()

        # To cache informal parcels,
        self._informal_parcels_info = tuple(
        )  # ([parcel_t_id: parcel_number], [,], [,], ...)
        self._informal_index = -1
        self._informal_parcels_len = 0  # To avoid calculating this each time

    def _add_layers(self):
        self.app.core.get_layers(self._db, self._layers, load=True)
        if not self._layers:
            self._restart_dict_of_layers()  # Let it ready for the next call
            return None

        # Layer was found, listen to its removal so that we can deactivate the custom tool when that occurs
        self.disconnect_plot_layer()
        self._layers[self._db.names.LC_PLOT_T].willBeDeleted.connect(
            self._plot_layer_removed)

        # Layer was found, listen to its removal so that we can update the variable properly
        self.disconnect_parcel_layer()
        self._layers[self._db.names.LC_PARCEL_T].willBeDeleted.connect(
            self._parcel_layer_removed)

        # Layer was found, listen to its removal so that we can update the variable properly
        try:
            self._layers[
                self._db.names.COL_UE_BAUNIT_T].willBeDeleted.disconnect(
                    self._uebaunit_table_removed)
        except:
            pass
        self._layers[self._db.names.COL_UE_BAUNIT_T].willBeDeleted.connect(
            self._uebaunit_table_removed)

    def _restart_dict_of_layers(self):
        self._layers = {
            self._db.names.LC_PLOT_T: None,
            self._db.names.LC_PARCEL_T: None,
            self._db.names.COL_UE_BAUNIT_T: None
        }

    def plot_layer(self):
        if self._layers[self._db.names.LC_PLOT_T] is None:
            self._add_layers()
        return self._layers[self._db.names.LC_PLOT_T]

    def parcel_layer(self):
        if self._layers[self._db.names.LC_PARCEL_T] is None:
            self._add_layers()
        return self._layers[self._db.names.LC_PARCEL_T]

    def uebaunit_table(self):
        if self._layers[self._db.names.COL_UE_BAUNIT_T] is None:
            self._add_layers()
        return self._layers[self._db.names.COL_UE_BAUNIT_T]

    def _plot_layer_removed(self):
        # The required layer was removed
        self.close_view_requested.emit()
        self._layers[self._db.names.LC_PLOT_T] = None

    def _parcel_layer_removed(self):
        self._layers[self._db.names.LC_PARCEL_T] = None

    def _uebaunit_table_removed(self):
        self._layers[self._db.names.COL_UE_BAUNIT_T] = None

    def disconnect_plot_layer(self):
        try:
            self._layers[self._db.names.LC_PLOT_T].willBeDeleted.disconnect(
                self._plot_layer_removed)
        except:
            pass

    def disconnect_parcel_layer(self):
        try:
            self._layers[self._db.names.LC_PARCEL_T].willBeDeleted.disconnect(
                self._parcel_layer_removed)
        except:
            pass

    def parcel_layer_name(self):
        return self._db.names.LC_PARCEL_T

    def t_id_name(self):
        return self._db.names.T_ID_F

    def parcel_number_name(self):
        return self._db.names.LC_PARCEL_T_PARCEL_NUMBER_F

    def previous_parcel_number_name(self):
        return self._db.names.LC_PARCEL_T_PREVIOUS_PARCEL_NUMBER_F

    def fmi_name(self):
        return self._db.names.LC_PARCEL_T_FMI_F

    def create_model(self, records):
        return TreeModel(self._db.names, data=records)

    def update_db_connection(self, db, ladm_col_db, db_source):
        self.close_view_requested.emit()

    def copy_value(self, value):
        self.clipboard.setText(str(value))

    def open_url(self, url):
        webbrowser.open(url)

    def zoom_to_feature(self, layer, t_id):
        self.zoom_to_features_requested.emit(layer, list(),
                                             {self._db.names.T_ID_F: [t_id]})

    def zoom_to_plots(self, plot_ids):
        self.zoom_to_features_requested.emit(self.plot_layer(), plot_ids,
                                             dict())

    def zoom_to_resulting_plots(self, records):
        # Zoom to plots retrieved from a search
        plot_t_ids = self._get_plot_t_ids_from_basic_info(records)
        if plot_t_ids:
            features = self._ladm_data.get_features_from_t_ids(
                self._layers[self._db.names.LC_PLOT_T], self._db.names.T_ID_F,
                plot_t_ids, True, True)
            plot_ids = [feature.id() for feature in features]
            self.zoom_to_features_requested.emit(self.plot_layer(), plot_ids,
                                                 dict())
            self.plot_layer().selectByIds(plot_ids)

    def _get_plot_t_ids_from_basic_info(self, records):
        res = []
        if records:
            if self._db.names.LC_PLOT_T in records:
                for element in records[self._db.names.LC_PLOT_T]:
                    res.append(element['id'])

        return res

    def open_feature_form(self, layer, t_id):
        # Note that it is important to fetch all feature attributes from the next call
        features = self._ladm_data.get_features_from_t_ids(
            layer, self._db.names.T_ID_F, [t_id], no_geometry=True)
        if features:
            self.app.gui.open_feature_form(layer, features[0])
        else:
            self.logger.warning(
                __name__,
                "No feature found in layer '{}' with t_id '{}'!!!".format(
                    layer.name(), t_id))

    def download_image(self, url):
        res = False
        img = None
        msg = {'text': '', 'level': Qgis.Warning}
        if url:
            self.logger.info(__name__, "Downloading file from {}".format(url))
            msg_status_bar = "Downloading image from document repository (this might take a while)..."
            with ProcessWithStatus(msg_status_bar):
                if is_connected(TEST_SERVER):

                    nam = QNetworkAccessManager()
                    request = QNetworkRequest(QUrl(url))
                    reply = nam.get(request)

                    loop = QEventLoop()
                    reply.finished.connect(loop.quit)
                    loop.exec_()

                    status = reply.attribute(
                        QNetworkRequest.HttpStatusCodeAttribute)
                    if status == 200:
                        res = True
                        img = reply.readAll()
                    else:
                        res = False
                        msg['text'] = QCoreApplication.translate(
                            "SettingsDialog",
                            "There was a problem connecting to the server. The server might be down or the service cannot be reached at the given URL."
                        )
                else:
                    res = False
                    msg['text'] = QCoreApplication.translate(
                        "SettingsDialog",
                        "There was a problem connecting to Internet.")

        else:
            res = False
            msg['text'] = QCoreApplication.translate("SettingsDialog",
                                                     "Not valid URL")

        if not res:
            self.logger.log_message(__name__, msg['text'], msg['level'])

        return res, img

    def get_plots_related_to_parcel(self, parcel_t_id):
        return self._ladm_data.get_plots_related_to_parcels(
            self._db, [parcel_t_id], None, self.plot_layer(),
            self.uebaunit_table())

    def get_layer(self, table_name):
        return self.app.core.get_layer(self._db, table_name, True)

    def search_data_basic_info(self, **kwargs):
        return self._ladm_queries.get_igac_basic_info(self._db, **kwargs)

    def search_data_legal_info(self, **kwargs):
        return self._ladm_queries.get_igac_legal_info(self._db, **kwargs)

    def search_data_physical_info(self, **kwargs):
        return self._ladm_queries.get_igac_physical_info(self._db, **kwargs)

    def search_data_economic_info(self, **kwargs):
        return self._ladm_queries.get_igac_economic_info(self._db, **kwargs)

    def query_informal_parcels(self):
        """
        :return: Triple --> parcel_number, current, total
        """
        # We always go to the DB to get informality info
        parcel_layer = self.app.core.get_layer(self._db,
                                               self._db.names.LC_PARCEL_T,
                                               True)
        informal_parcel_t_ids = self._ladm_data.get_informal_parcel_tids(
            self._db, parcel_layer)

        # Overwrite cache
        self._informal_parcels_info = tuple()
        self._informal_index = -1
        self._informal_parcels_len = 0

        if informal_parcel_t_ids:
            # Get parcel info ordered by parcel number
            parcels = self._ladm_data.get_features_from_t_ids(
                self.parcel_layer(),
                self._db.names.T_ID_F,
                informal_parcel_t_ids,
                no_attributes=False,
                no_geometry=False,
                only_attributes=[self._db.names.LC_PARCEL_T_PARCEL_NUMBER_F],
                order_by=self._db.names.LC_PARCEL_T_PARCEL_NUMBER_F)

            # Create a tuple of lists ([t_id: parcel_number], ...)
            self._informal_parcels_info = tuple([
                p[self._db.names.T_ID_F], p[
                    self._db.names.LC_PARCEL_T_PARCEL_NUMBER_F]
            ] for p in parcels)
            self._informal_parcels_len = len(self._informal_parcels_info)

        return self.get_next_informal_parcel()

    def get_next_informal_parcel(self):
        return self._traverse_informal_parcel_info()

    def get_previous_informal_parcel(self):
        return self._traverse_informal_parcel_info(False)

    def _traverse_informal_parcel_info(self, next=True):
        """
        Get a triple corresponding to an informal parcel number, the current index and the total of parcels.
        Note that if we get to the end and ask for the next parcel, we start over again. Similarly. if we are in the 1st
        parcel and ask for the previous one, then we get the latest one.

        :param next: Whether we need the next parcel's info or the previous one.
        :return: Triple --> parcel_number, current_idx, total_parcels (the current_idx returned is for display purposes)
        """
        if not self._informal_parcels_len:
            return '', 0, 0

        index = self._informal_index  # Get current index

        if next:  # Now set the current index
            self._informal_index = index + 1 if index + 1 < self._informal_parcels_len else 0
        else:  # Previous
            self._informal_index = index - 1 if index >= 1 else self._informal_parcels_len - 1

        return self._informal_parcels_info[self._informal_index][
            1], self._informal_index + 1, self._informal_parcels_len