# Source code for svir.dialogs.upload_dialog

    # -*- coding: utf-8 -*-
    # /***************************************************************************
    # Irmt
    #                                 A QGIS plugin
    # OpenQuake Integrated Risk Modelling Toolkit
    #                              -------------------
    #        begin                : 2013-10-24
    #        copyright            : (C) 2014-2015 by GEM Foundation
    #        email                : devops@openquake.org
    # ***************************************************************************/
    #
    # OpenQuake is free software: you can redistribute it and/or modify it
    # under the terms of the GNU Affero General Public License as published
    # by the Free Software Foundation, either version 3 of the License, or
    # (at your option) any later version.
    #
    # OpenQuake is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU Affero General Public License
    # along with OpenQuake.  If not, see <http://www.gnu.org/licenses/>.

    import os
    import traceback
    from qgis.core import QgsRuleBasedRenderer, Qgis
    from qgis.gui import QgsMessageBar

    from qgis.PyQt.QtCore import Qt, QUrl, QSettings, pyqtSignal
    from qgis.PyQt.QtWidgets import QDialog, QSizePolicy, QDialogButtonBox
    from qgis.PyQt.QtNetwork import QNetworkCookieJar, QNetworkCookie
    from qgis.PyQt.QtWebKit import QWebSettings

    from svir.thread_worker.abstract_worker import start_worker
    from svir.thread_worker.upload_worker import UploadWorker

    from requests.sessions import Session
    from requests.utils import dict_from_cookiejar

    from svir.utilities.sldadapter import getGsCompatibleSld
    from svir.utilities.utils import (platform_login,
                                      create_progress_message_bar,
                                      clear_progress_message_bar,
                                      SvNetworkError,
                                      log_msg,
                                      get_ui_class,
                                      get_credentials,
                                      )
    from svir.utilities.shared import DEBUG

    FORM_CLASS = get_ui_class('ui_upload_metadata.ui')

    class UploadDialog(QDialog, FORM_CLASS):
        """
        Modal dialog allowing to upload the data to the OQ-Platform
        """

        upload_successful = pyqtSignal(str)

        def __init__(self, iface, file_stem):
            self.iface = iface
            QDialog.__init__(self)

            # Set up the user interface from Designer.
            self.setupUi(self)
            self.message_bar = QgsMessageBar()
            self.message_bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
            self.layout().insertWidget(0, self.message_bar)

            self.message_bar_item = None

            self.button_box = self.buttonBox

            self.hostname, self.username, self.password = get_credentials(
                'platform')

            self.web_view = self.web_view
            self.page = self.web_view.page()
            self.frame = self.page.mainFrame()

            self.session = Session()
            self.network_access_manager = self.page.networkAccessManager()
            self.cookie_jar = QNetworkCookieJar()
            self.network_access_manager.setCookieJar(self.cookie_jar)

            self._setup_context_menu()
            self.frame.javaScriptWindowObjectCleared.connect(self._setup_js)

            self.file_stem = file_stem

            self.layout().setContentsMargins(0, 0, 0, 0)

            self.web_view.loadFinished.connect(self.load_finished)

            self.layer_url = None

        def showEvent(self, event):
            super(UploadDialog, self).showEvent(event)
            self.upload()

        def upload(self):
            try:
                self._login_to_platform()
            except SvNetworkError as e:
                error_msg = (
                    'Unable to login to the platform: ' + e.message)
                self.message_bar.pushMessage(
                    'Error', error_msg, duration=0, level=Qgis.Critical)
                return

            # adding by emitting signal in different thread
            worker = UploadWorker(
                self.hostname, self.session, self.file_stem,
                self.username, self.iface.activeLayer())

            worker.successfully_finished.connect(self.upload_done)
            start_worker(worker, self.message_bar, 'Uploading data')

        def _update_layer_style(self):
            # The file stem contains the full path. We get just the basename
            layer_name = os.path.basename(self.file_stem)
            # Since the style name is set by default substituting '-' with '_',
            # tp get the right style we need to do the same substitution
            style_name = layer_name.replace('-', '_')
            try:
                sld = getGsCompatibleSld(self.iface.activeLayer(), style_name)
            except Exception as e:
                error_msg = (
                    'Unable to export the styled layer descriptor: ' + str(e))
                log_msg(error_msg, level='C', message_bar=self.message_bar,
                        exception=e)
                return

            if DEBUG:
                import tempfile
                fd, fname = tempfile.mkstemp(suffix=".sld")
                os.close(fd)
                with open(fname, 'w', newline='') as f:
                    f.write(sld)
                os.system('tidy -xml -i %s' % fname)
            headers = {'content-type': 'application/vnd.ogc.sld+xml'}
            # NOTE: to save the style, we actually need to do both the post and the
            # put in this sequence, otherwise it doesn't work.  We still haven't
            # found any better way to obtain the same correct behavior
            resp = self.session.post(
                    self.hostname + '/gs/rest/styles/%s.sld' % style_name,
                    data=sld, headers=headers)
            resp = self.session.put(
                    self.hostname + '/gs/rest/styles/%s.sld' % style_name,
                    data=sld, headers=headers)
            if DEBUG:
                log_msg('Style upload response: %s' % resp)
            if not resp.ok:
                error_msg = (
                    'Error while styling the uploaded layer: ' + resp.reason)
                self.message_bar.pushMessage(
                    'Style error', error_msg, duration=0,
                    level=Qgis.Critical)
            select_style_xml = """
    <layer>
        <name>oqplatform:%s</name>
        <defaultStyle>
            <name>%s</name>
            <atom:link xmlns:atom="http://www.w3.org/2005/Atom"
                rel="alternate"
                href="http://127.0.0.1:8080/geoserver/rest/styles/%s.xml"
                type="application/xml"/>
        </defaultStyle>
    </layer>""" % (style_name, style_name, style_name)
            headers = {'content-type': 'text/xml'}
            resp = self.session.put(
                self.hostname + '/gs/rest/layers/%s.xml' % style_name,
                data=select_style_xml,
                headers=headers)
            if DEBUG:
                log_msg('Style selection response: %s' % resp)
            if not resp.ok:
                error_msg = (
                    'Error while selecting the style of the loaded layer: '
                    + resp.reason)
                self.message_bar.pushMessage(
                    'Style error', error_msg, duration=0,
                    level=QgsMessageBar.CRITICAL)

        def upload_done(self, result):
            layer_url, success = result
            # In case success == 'False', layer_url contains the error message
            if success:
                # so far, we implemented the style-converter only for the
                # rule-based styles. Only in those cases, we should add a style to
                # the layer to be uploaded. Otherwise, it's fine to use the default
                # basic geonode style.
                if isinstance(self.iface.activeLayer().renderer(),
                              QgsRuleBasedRenderer):
                    self._update_layer_style()
                else:
                    self.message_bar.pushMessage(
                        'Info',
                        'Using the basic default style',
                        level=Qgis.Info)
                self.message_bar_item, _ = create_progress_message_bar(
                    self.message_bar, 'Loading page......', no_percentage=True)
                self.web_view.load(QUrl(layer_url))
                self.layer_url = layer_url
                self.upload_successful.emit(layer_url)
            else:
                error_msg = layer_url
                clear_progress_message_bar(self.message_bar)
                self.message_bar.pushMessage(
                    'Upload error', error_msg, duration=0,
                    level=Qgis.Critical)

        def load_finished(self):
            clear_progress_message_bar(self.message_bar, self.message_bar_item)
            if not self.button_box.isEnabled():
                self.button_box.setEnabled(True)
                self.button_box.addButton('Close',
                                          QDialogButtonBox.NoRole)
                self.button_box.addButton('Close and show in browser',
                                          QDialogButtonBox.YesRole)

        def _login_to_platform(self):
            self.hostname, self.username, self.password = get_credentials(
                'platform')
            platform_login(
                self.hostname, self.username, self.password, self.session)
            sessionid = dict_from_cookiejar(self.session.cookies)['sessionid']
            sessionid_cookie = QNetworkCookie(
                b'sessionid', sessionid.encode('utf8'))
            self.cookie_jar.setCookiesFromUrl(
                [sessionid_cookie], QUrl(self.hostname))

        def _setup_context_menu(self):
            settings = QSettings()
            developer_mode = settings.value(
                '/irmt/developer_mode', True, type=bool)
            if developer_mode is True:
                self.web_view.page().settings().setAttribute(
                    QWebSettings.DeveloperExtrasEnabled, True)
            else:
                self.web_view.setContextMenuPolicy(Qt.NoContextMenu)

        def _setup_js(self):
            # pass a reference (called qt_page) of self to the JS world
            # to expose a member of self to js you need to declare it as property
            # see for example self.json_str()
            self.frame.addToJavaScriptWindowObject('qt_page', self)