class Geo360Dialog(QDockWidget, Ui_orbitalDialog):
    """Geo360 Dialog Class"""
    def __init__(self, iface, parent=None, featuresId=None, layer=None):

        QDockWidget.__init__(self)

        self.setupUi(self)

        self.DEFAULT_URL = ("http://" + config.IP + ":" + str(config.PORT) +
                            "/viewer.html")
        self.DEFAULT_EMPTY = ("http://" + config.IP + ":" + str(config.PORT) +
                              "/none.html")
        self.DEFAULT_BLANK = ("http://" + config.IP + ":" + str(config.PORT) +
                              "/blank.html")

        # Create Viewer
        self.CreateViewer()

        self.plugin_path = os.path.dirname(os.path.realpath(__file__))
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.parent = parent

        # Orientation from image
        self.yaw = math.pi
        self.bearing = None

        self.layer = layer
        self.featuresId = featuresId

        self.actualPointDx = None
        self.actualPointSx = None
        self.actualPointOrientation = None

        self.selected_features = qgsutils.getToFeature(self.layer,
                                                       self.featuresId)

        # Get image path
        self.current_image = self.GetImage()

        # Check if image exist
        if os.path.exists(self.current_image) is False:
            qgsutils.showUserAndLogMessage(u"Information: ",
                                           u"There is no associated image.")
            self.resetQgsRubberBand()
            self.ChangeUrlViewer(self.DEFAULT_EMPTY)
            return

        # Copy file to local server
        self.CopyFile(self.current_image)

        # Set RubberBand
        self.resetQgsRubberBand()
        self.setOrientation()
        self.setPosition()

    """Update data from Marzipano Viewer"""

    def onNewData(self, data):
        try:
            newYaw = float(data[0])
            self.UpdateOrientation(yaw=newYaw)
        except:
            None

    def CreateViewer(self):
        """Create Viewer"""
        qgsutils.showUserAndLogMessage(u"Information: ",
                                       u"Create viewer",
                                       onlyLog=True)

        self.cef_widget = QWebView()
        self.cef_widget.setContextMenuPolicy(Qt.NoContextMenu)

        self.cef_widget.settings().setAttribute(QWebSettings.JavascriptEnabled,
                                                True)
        pano_view_settings = self.cef_widget.settings()
        pano_view_settings.setAttribute(QWebSettings.WebGLEnabled, True)
        # pano_view_settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)
        pano_view_settings.setAttribute(
            QWebSettings.Accelerated2dCanvasEnabled, True)
        pano_view_settings.setAttribute(QWebSettings.JavascriptEnabled, True)

        self.page = _ViewerPage()
        self.page.newData.connect(self.onNewData)
        self.cef_widget.setPage(self.page)

        self.cef_widget.load(QUrl(self.DEFAULT_URL))
        self.ViewerLayout.addWidget(self.cef_widget, 1, 0)

    # def SetInitialYaw(self):
    #     """Set Initial Viewer Yaw"""
    #     self.bearing = self.selected_features.attribute(config.column_yaw)
    #     # self.view.browser.GetMainFrame().ExecuteFunction("InitialYaw",
    #     #                                                  self.bearing)
    #     return

    def RemoveImage(self):
        """Remove Image"""
        try:
            os.remove(self.plugin_path + "/viewer/image.jpg")
        except OSError:
            pass

    def CopyFile(self, src):
        """Copy Image File in Local Server"""
        qgsutils.showUserAndLogMessage(u"Information: ",
                                       u"Copying image",
                                       onlyLog=True)

        src_dir = src
        dst_dir = self.plugin_path + "/viewer"

        # Copy image in local folder
        img = Image.open(src_dir)
        rgb_im = img.convert("RGB")
        dst_dir = dst_dir + "/image.jpg"

        try:
            os.remove(dst_dir)
        except OSError:
            pass

        rgb_im.save(dst_dir)

    def GetImage(self):
        """Get Selected Image"""
        try:
            path = qgsutils.getAttributeFromFeature(self.selected_features,
                                                    config.column_name)
            if not os.path.isabs(path):  # Relative Path to Project
                path_project = QgsProject.instance().readPath("./")
                path = os.path.normpath(os.path.join(path_project, path))
        except Exception:
            qgsutils.showUserAndLogMessage(u"Information: ",
                                           u"Column not found.")
            return

        qgsutils.showUserAndLogMessage(u"Information: ",
                                       str(path),
                                       onlyLog=True)
        return path

    def ChangeUrlViewer(self, new_url):
        """Change Url Viewer"""
        self.cef_widget.load(QUrl(new_url))

    def ReloadView(self, newId):
        """Reaload Image viewer"""
        self.setWindowState(self.windowState() & ~Qt.WindowMinimized
                            | Qt.WindowActive)
        # this will activate the window
        self.activateWindow()
        self.selected_features = qgsutils.getToFeature(self.layer, newId)

        self.current_image = self.GetImage()

        # Check if image exist
        if os.path.exists(self.current_image) is False:
            qgsutils.showUserAndLogMessage(u"Information: ",
                                           u"There is no associated image.")
            self.ChangeUrlViewer(self.DEFAULT_EMPTY)
            self.resetQgsRubberBand()
            return

        # Set RubberBand
        self.resetQgsRubberBand()
        self.setOrientation()
        self.setPosition()

        # Copy file to local server
        self.CopyFile(self.current_image)

        self.ChangeUrlViewer(self.DEFAULT_URL)

    def GetBackNextImage(self):
        """Get to Back Image"""
        sender = QObject.sender(self)

        lys = self.canvas.layers()  # Check if mapa foto is loaded
        if len(lys) == 0:
            qgsutils.showUserAndLogMessage(u"Information: ",
                                           u"You need load the photo layer.")
            return

        for layer in lys:
            if layer.name() == config.layer_name:
                self.encontrado = True
                self.iface.setActiveLayer(layer)

                f = self.selected_features

                ac_lordem = f.attribute(config.column_order)

                if sender.objectName() == "btn_back":
                    new_lordem = int(ac_lordem) - 1
                else:
                    new_lordem = int(ac_lordem) + 1

                # Filter mapa foto layer
                ids = [
                    feat.id() for feat in layer.getFeatures(QgsFeatureRequest(
                    ).setFilterExpression(config.column_order + " ='" +
                                          str(new_lordem) + "'"))
                ]

                if len(ids) == 0:
                    qgsutils.showUserAndLogMessage(
                        u"Information: ",
                        u"There is no superiority that follows.")
                    # Filter mapa foto layer
                    ids = [
                        feat.id()
                        for feat in layer.getFeatures(QgsFeatureRequest(
                        ).setFilterExpression(config.column_order + " ='" +
                                              str(ac_lordem) + "'"))
                    ]
                # Update selected feature
                self.ReloadView(ids[0])

        if self.encontrado is False:
            qgsutils.showUserAndLogMessage(
                u"Information: ",
                u"You need a layer with images and set the name in the config.py file.",
            )

        return

    def FullScreen(self, value):
        """FullScreen action button"""
        qgsutils.showUserAndLogMessage(u"Information: ",
                                       u"Fullscreen.",
                                       onlyLog=True)
        if value:
            self.showFullScreen()
        else:
            self.showNormal()

    def UpdateOrientation(self, yaw=None):
        """Update Orientation"""
        self.bearing = self.selected_features.attribute(config.column_yaw)
        try:
            self.actualPointOrientation.reset()
        except Exception:
            pass

        self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(),
                                                    QgsWkbTypes.LineGeometry)
        self.actualPointOrientation.setColor(Qt.blue)
        self.actualPointOrientation.setWidth(5)
        self.actualPointOrientation.addPoint(self.actualPointDx)

        # End Point
        CS = self.canvas.mapUnitsPerPixel() * 25
        A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2)
        A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2)

        self.actualPointOrientation.addPoint(QgsPointXY(
            float(A1x), float(A1y)))

        # Vision Angle
        if yaw is not None:
            angle = float(self.bearing + yaw) * math.pi / -180
        else:
            angle = float(self.bearing) * math.pi / -180

        tmpGeom = self.actualPointOrientation.asGeometry()
        rotatePoint = self.rotateTool.rotate(tmpGeom, self.actualPointDx,
                                             angle)

        self.actualPointOrientation.setToGeometry(rotatePoint, self.dumLayer)
        # Set Azimut value
        tmpGeom = rotatePoint.asPolyline()
        azim = tmpGeom[0].azimuth(tmpGeom[1])
        if azim < 0:
            azim += 360
        self.yawLbl.setText("Yaw : " + str(round(yaw, 2)) + " Azimut : " +
                            str(round(azim, 2)))

    def setOrientation(self, yaw=None):
        """Set Orientation in the firt time"""
        self.bearing = self.selected_features.attribute(config.column_yaw)

        originalPoint = self.selected_features.geometry().asPoint()
        self.actualPointDx = qgsutils.convertProjection(
            originalPoint.x(),
            originalPoint.y(),
            self.layer.crs().authid(),
            self.canvas.mapSettings().destinationCrs().authid(),
        )

        self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(),
                                                    QgsWkbTypes.LineGeometry)
        self.actualPointOrientation.setColor(Qt.blue)
        self.actualPointOrientation.setWidth(5)

        self.actualPointOrientation.addPoint(self.actualPointDx)

        # End Point
        CS = self.canvas.mapUnitsPerPixel() * 25
        A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2)
        A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2)

        self.actualPointOrientation.addPoint(QgsPointXY(
            float(A1x), float(A1y)))
        # Vision Angle
        if yaw is not None:
            angle = float(self.bearing + yaw) * math.pi / -180
        else:
            angle = float(self.bearing) * math.pi / -180

        tmpGeom = self.actualPointOrientation.asGeometry()

        self.rotateTool = transformGeometry()
        epsg = self.canvas.mapSettings().destinationCrs().authid()
        self.dumLayer = QgsVectorLayer("Point?crs=" + epsg, "temporary_points",
                                       "memory")
        self.actualPointOrientation.setToGeometry(
            self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle),
            self.dumLayer)

    def setPosition(self):
        """Set RubberBand Position"""
        # Transform Point
        originalPoint = self.selected_features.geometry().asPoint()
        self.actualPointDx = qgsutils.convertProjection(
            originalPoint.x(),
            originalPoint.y(),
            "EPSG:4326",
            self.canvas.mapSettings().destinationCrs().authid(),
        )

        self.positionDx = QgsRubberBand(self.iface.mapCanvas(),
                                        QgsWkbTypes.PointGeometry)
        self.positionDx.setWidth(6)
        self.positionDx.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.positionDx.setIconSize(6)
        self.positionDx.setColor(Qt.black)
        self.positionSx = QgsRubberBand(self.iface.mapCanvas(),
                                        QgsWkbTypes.PointGeometry)
        self.positionSx.setWidth(5)
        self.positionSx.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.positionSx.setIconSize(4)
        self.positionSx.setColor(Qt.blue)
        self.positionInt = QgsRubberBand(self.iface.mapCanvas(),
                                         QgsWkbTypes.PointGeometry)
        self.positionInt.setWidth(5)
        self.positionInt.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.positionInt.setIconSize(3)
        self.positionInt.setColor(Qt.white)

        self.positionDx.addPoint(self.actualPointDx)
        self.positionSx.addPoint(self.actualPointDx)
        self.positionInt.addPoint(self.actualPointDx)

    def closeEvent(self, _):
        """Close dialog"""
        self.resetQgsRubberBand()
        self.canvas.refresh()
        self.iface.actionPan().trigger()
        self.parent.orbitalViewer = None
        self.RemoveImage()

    def resetQgsRubberBand(self):
        """Remove RubbeBand"""
        try:
            self.yawLbl.setText("")
            self.positionSx.reset()
            self.positionInt.reset()
            self.positionDx.reset()
            self.actualPointOrientation.reset()
        except Exception:
            None
class QgepPlotSVGWidget(QWidget):
    webView = None
    webPage = None
    frame = None
    profile = None
    verticalExaggeration = 10
    jsTranslator = QgepJsTranslator()

    # Signals emitted triggered by javascript actions
    reachClicked = pyqtSignal([str], name='reachClicked')
    reachMouseOver = pyqtSignal([str], name='reachMouseOver')
    reachMouseOut = pyqtSignal([str], name='reachMouseOut')
    reachPointClicked = pyqtSignal([str, str], name='reachPointClicked')
    reachPointMouseOver = pyqtSignal([str, str], name='reachPointMouseOver')
    reachPointMouseOut = pyqtSignal([str, str], name='reachPointMouseOut')
    specialStructureClicked = pyqtSignal([str], name='specialStructureClicked')
    specialStructureMouseOver = pyqtSignal([str],
                                           name='specialStructureMouseOver')
    specialStructureMouseOut = pyqtSignal([str],
                                          name='specialStructureMouseOut')

    # Signals emitted for javascript
    profileChanged = pyqtSignal([str], name='profileChanged')
    verticalExaggerationChanged = pyqtSignal(
        [int], name='verticalExaggerationChanged')

    def __init__(self,
                 parent,
                 network_analyzer: QgepGraphManager,
                 url: str = None):
        QWidget.__init__(self, parent)

        self.webView = QWebView()
        self.webView.setPage(QgepWebPage(self.webView))

        self.networkAnalyzer = network_analyzer

        settings = QSettings()

        layout = QVBoxLayout(self)
        if url is None:
            # Starting with QGIS 3.4, QWebView requires paths with / even on windows.
            default_url = plugin_root_path().replace(
                '\\', '/') + '/svgprofile/index.html'
            url = settings.value("/QGEP/SvgProfilePath", default_url)
            url = 'file:///' + url

        developer_mode = settings.value("/QGEP/DeveloperMode",
                                        False,
                                        type=bool)

        if developer_mode is True:
            self.webView.page().settings().setAttribute(
                QWebSettings.DeveloperExtrasEnabled, True)
        else:
            self.webView.setContextMenuPolicy(Qt.NoContextMenu)

        self.webView.load(QUrl(url))
        self.frame = self.webView.page().mainFrame()
        self.frame.javaScriptWindowObjectCleared.connect(self.initJs)

        layout.addWidget(self.webView)

    def setProfile(self, profile):
        self.profile = profile
        # Forward to javascript
        self.profileChanged.emit(profile.asJson())

    def initJs(self):
        self.frame.addToJavaScriptWindowObject("profileProxy", self)
        self.frame.addToJavaScriptWindowObject("i18n", self.jsTranslator)

    def changeVerticalExaggeration(self, val):
        self.verticalExaggeration = val
        self.verticalExaggerationChanged.emit(val)

    def printProfile(self):
        printer = QPrinter(QPrinter.HighResolution)
        printer.setOutputFormat(QPrinter.PdfFormat)
        printer.setPaperSize(QPrinter.A4)
        printer.setOrientation(QPrinter.Landscape)

        printpreviewdlg = QPrintPreviewDialog()
        printpreviewdlg.paintRequested.connect(self.printRequested)

        printpreviewdlg.exec_()

    @pyqtSlot(QPrinter)
    def printRequested(self, printer):
        self.webView.print_(printer)

    @pyqtSlot(str)
    def onReachClicked(self, obj_id):
        self.reachClicked.emit(obj_id)

    @pyqtSlot(str)
    def onReachMouseOver(self, obj_id):
        self.reachMouseOver.emit(obj_id)

    @pyqtSlot(str)
    def onReachMouseOut(self, obj_id):
        self.reachMouseOut.emit(obj_id)

    @pyqtSlot(str, str)
    def onReachPointClicked(self, obj_id, reach_obj_id):
        self.reachPointClicked.emit(obj_id, reach_obj_id)

    @pyqtSlot(str, str)
    def onReachPointMouseOver(self, obj_id, reach_obj_id):
        self.reachPointMouseOver.emit(obj_id, reach_obj_id)

    @pyqtSlot(str, str)
    def onReachPointMouseOut(self, obj_id, reach_obj_id):
        self.reachPointMouseOut.emit(obj_id, reach_obj_id)

    @pyqtSlot(str)
    def onSpecialStructureClicked(self, obj_id):
        self.specialStructureClicked.emit(obj_id)

    @pyqtSlot(str)
    def onSpecialStructureMouseOver(self, obj_id):
        self.specialStructureMouseOver.emit(obj_id)

    @pyqtSlot(str)
    def onSpecialStructureMouseOut(self, obj_id):
        self.specialStructureMouseOut.emit(obj_id)

    # Is called from the webView when it's been reloaded and wants to have the
    # profile information resent
    @pyqtSlot()
    def updateProfile(self):
        if self.profile:
            self.profileChanged.emit(self.profile.asJson())
            self.verticalExaggerationChanged.emit(self.verticalExaggeration)