# -*- coding: utf-8 -*-
"""
/***************************************************************************
 CIGeoEMirrorView
                                 A QGIS plugin
 Add one or more panels synchronized with the main panel.
Adapted from plugin DockableMirrorMap (homepage=http://www.faunalia.com/)

 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2019-12-04
        git sha              : $Format:%H$
        copyright            : (C) 2019 by Centro de Informação Geoespacial do Exército 
        email                : igeoe@igeoe.pt
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from qgis.PyQt.QtXml import QDomDocument
from qgis.gui import *
from qgis.core import *

# Initialize Qt resources from file resources.py
from .resources import *
# Import the code for the dialog
from .CIGeoE_Mirror_View_dialog import CIGeoEMirrorViewDialog
import os.path


class CIGeoEMirrorView:
    """QGIS Plugin Implementation."""
    
    def __init__(self, iface):
        """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',
            'CIGeoEMirrorView_{}.qm'.format(locale))

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

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&CIGeoE Mirror View')


        cigeoeToolBarExists = False
        for x in iface.mainWindow().findChildren(QToolBar): 
            if x.windowTitle() == 'CIGeoE':
                self.toolbar = x
                cigeoeToolBarExists = True
        if cigeoeToolBarExists==False:
            self.toolbar = self.iface.addToolBar(u'CIGeoE')
           
        self.toolbar.setObjectName(u'CIGeoEMirrorView')


        # 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

        self.pluginIsActive = False

    # 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('CIGeoEMirrorView', 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)
            self.toolbar.addAction(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/CIGeoE_Mirror_View/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(u'CIGeoEMirrorView: Add one or more panels synchronized with the main panel.'),
            callback=self.run,
            parent=self.iface.mainWindow())

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

           
        #-------------------------------------------
        self.dockableMirrors = []
        self.lastDockableMirror = 0       

		#QObject.connect(self.iface, SIGNAL("projectRead()"), self.onProjectLoaded)                              # qgis2
		#QObject.connect(QgsProject.instance(), SIGNAL("writeProject(QDomDocument &)"), self.onWriteProject)     # qgis2
        self.iface.projectRead.connect(self.onProjectLoaded)                                                    # qgis3
        QgsProject.instance().writeProject.connect(self.onWriteProject)                          				# qgis3

        #-------------------------------------------
     

    def unload(self):        
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&CIGeoE Mirror View'),
                action)
            self.iface.removeToolBarIcon(action)
      
        # remove the toolbar
        del self.toolbar

		#QObject.disconnect(self.iface, SIGNAL("projectRead()"), self.onProjectLoaded)                              # qgis2
		#QObject.disconnect(QgsProject.instance(), SIGNAL("writeProject(QDomDocument &)"), self.onWriteProject)     # qgis2
        self.iface.projectRead.disconnect(self.onProjectLoaded)                                                     # qgis3                
        QgsProject.instance().writeProject.disconnect(self.onWriteProject)                          				# qgis3

        
    def removeDockableMirrors(self):
        for d in list(self.dockableMirrors):
        	d.close()
        	self.iface.removeDockWidget(d)
        self.dockableMirrors = []
        self.lastDockableMirror = 0


	
    def run(self):        
        """Run method that performs all the real work"""

        layers = self.iface.mapCanvas().layers() 
        if not layers:        
            QMessageBox.information(self.iface.mainWindow(), "Error", 'Layer is not loaded!')            
            return 	

        self.first_start = False

        
        from .dockableMirrorView import DockableMirrorView
        wdg = DockableMirrorView(self.iface.mainWindow(), self.iface)

        minsize = wdg.minimumSize()
        maxsize = wdg.maximumSize()

        self.setupDockWidget(wdg)	        
        self.addDockWidget(wdg)

        wdg.setMinimumSize(minsize)
        wdg.setMaximumSize(maxsize)

        if wdg.isFloating():
            wdg.move(50, 50)	# move the widget to the center
            
    
    def setupDockWidget(self, wdg):
        othersize = QGridLayout().verticalSpacing()
        if len(self.dockableMirrors) <= 0:
            width = self.iface.mapCanvas().size().width()/2 - othersize
            wdg.setLocation( Qt.RightDockWidgetArea )
            wdg.setMinimumWidth( width )
            wdg.setMaximumWidth( width )

        elif len(self.dockableMirrors) == 1:
            height = self.dockableMirrors[0].size().height()/2 - othersize/2
            wdg.setLocation( Qt.RightDockWidgetArea )
            wdg.setMinimumHeight( height )
            wdg.setMaximumHeight( height )

        elif len(self.dockableMirrors) == 2:
            height = self.iface.mapCanvas().size().height()/2 - othersize/2
            wdg.setLocation( Qt.BottomDockWidgetArea )
            wdg.setMinimumHeight( height )
            wdg.setMaximumHeight( height )

        else:
            wdg.setLocation( Qt.BottomDockWidgetArea )
            wdg.setFloating( True )

    
    def addDockWidget(self, wdg, position=None):     
        if position == None:
            position = wdg.getLocation()
        else:
            wdg.setLocation( position )
        
        mapCanvas = self.iface.mapCanvas()
        oldSize = mapCanvas.size()

        prevFlag = mapCanvas.renderFlag()
        mapCanvas.setRenderFlag(False)
        self.iface.addDockWidget(position, wdg)

        wdg.setNumber( self.lastDockableMirror )
        self.lastDockableMirror = self.lastDockableMirror+1
        self.dockableMirrors.append( wdg )
                
        closed = pyqtSignal('PyQt_PyObject')                     
        wdg.closed.connect(self.onCloseDockableMirror)           
                
        newSize = mapCanvas.size()
        if newSize != oldSize:
            # trick: update the canvas size
            mapCanvas.resize(newSize.width() - 1, newSize.height())
            mapCanvas.setRenderFlag(prevFlag)
            mapCanvas.resize(newSize)
        else:
            mapCanvas.setRenderFlag(prevFlag)


    def onCloseDockableMirror(self, wdg):         # close dockable          
        if self.dockableMirrors.count( wdg ) > 0:
            self.dockableMirrors.remove( wdg )
        
        if len(self.dockableMirrors) <= 0:
            self.lastDockableMirror = 0

        
    #def onWriteProject(self, domproject):                              # qgis2
    def onWriteProject(self):
        if len(self.dockableMirrors) <= 0:
            return

        QgsProject.instance().writeEntry( "DockableMirrorView", "/numMirrors", len(self.dockableMirrors) )
        for i, dockwidget in enumerate(self.dockableMirrors):		
        	# save position and geometry
        	floating = dockwidget.isFloating()
        	QgsProject.instance().writeEntry( "DockableMirrorView", "/mirror%s/floating" % i, floating )
        	if floating:
        		position = "%s %s" % (dockwidget.pos().x(), dockwidget.pos().y())
        	else:
        		position = u"%s" % dockwidget.getLocation()
        	QgsProject.instance().writeEntry( "DockableMirrorView", "/mirror%s/position" % i, str(position) )

        	size = "%s %s" % (dockwidget.size().width(), dockwidget.size().height())
        	QgsProject.instance().writeEntry( "DockableMirrorView", "/mirror%s/size" % i, str(size) )

        	QgsProject.instance().writeEntry( "DockableMirrorView", "/mirror%s/label" % i, dockwidget.getMirror().label )

        	# save the layer list
        	layerIds = dockwidget.getMirror().getLayerSet()
        	QgsProject.instance().writeEntry( "DockableMirrorView", "/mirror%s/layers" % i, layerIds )

        	scaleFactor = dockwidget.getMirror().scaleFactor.value()
        	QgsProject.instance().writeEntryDouble("DockableMirrorView", "/mirror%s/scaleFactor" % i, scaleFactor)

        	# layer style overrides
        	keys = []
        	values = []
        	#for k,v in dockwidget.getMirror().overrides.iteritems():       # qgis2
        	for k,v in dockwidget.getMirror().overrides.items():
        	    keys.append(k)
        	    values.append(v)

        	QgsProject.instance().writeEntry("DockableMirrorView", "/mirror%s/layerStylesKeys" % i, keys)
        	QgsProject.instance().writeEntry("DockableMirrorView", "/mirror%s/layerStylesValues" % i, values)
            

    def onProjectLoaded(self):
        # restore mirrors?        	
        num, ok = QgsProject.instance().readNumEntry("DockableMirrorView", "/numMirrors")
        if not ok or num <= 0:
            return

        # remove all mirrors
        self.removeDockableMirrors()        

        mirror2lids = {}
        # load mirrors

        for i in range(num):            
            if num >= 2:
                if i == 0:
                    prevFlag = self.iface.mapCanvas().renderFlag()
                    self.iface.mapCanvas().setRenderFlag(False)
                elif i == num-1:
                    self.iface.mapCanvas().setRenderFlag(True)
            
            from .dockableMirrorView import DockableMirrorView
            dockwidget = DockableMirrorView(self.iface.mainWindow(), self.iface)

            minsize = dockwidget.minimumSize()
            maxsize = dockwidget.maximumSize()        

            # restore position
            floating, ok = QgsProject.instance().readBoolEntry("DockableMirrorView", "/mirror%s/floating" % i)
            if ok: 
                dockwidget.setFloating( floating )
                position, ok = QgsProject.instance().readEntry("DockableMirrorView", "/mirror%s/position" % i)
                if ok:
                    try:
                        if floating:
                            parts = position.split(" ")
                            if len(parts) >= 2:
                                dockwidget.move( int(parts[0]), int(parts[1]) )
                        else:
                            dockwidget.setLocation( int(position) )
                    except ValueError:
                        pass
                
            # restore geometry
            dockwidget.setFixedSize( dockwidget.geometry().width(), dockwidget.geometry().height() )
            size, ok = QgsProject.instance().readEntry("DockableMirrorView", "/mirror%s/size" % i)
            if ok:
                try:
                    parts = size.split(" ")
                    dockwidget.setFixedSize( int(parts[0]), int(parts[1]) )
                except ValueError:
                    pass

            label, ok = QgsProject.instance().readEntry( "DockableMirrorView", "/mirror%s/label" % i )
            if ok:
                dockwidget.getMirror().label = label

            scaleFactor, ok = QgsProject.instance().readDoubleEntry("DockableMirrorView", "/mirror%s/scaleFactor" % i, 1.0)
            if ok: dockwidget.getMirror().scaleFactor.setValue( scaleFactor )

            # get layer list
            layerIds, ok = QgsProject.instance().readListEntry("DockableMirrorView", "/mirror%s/layers" % i)
            if ok: dockwidget.getMirror().setLayerSet( layerIds )

            # layer style overrides
            keys, ok = QgsProject.instance().readListEntry("DockableMirrorView", "/mirror%s/layerStylesKeys" % i)
            values, ok = QgsProject.instance().readListEntry("DockableMirrorView", "/mirror%s/layerStylesValues" % i)
            if ok and len(keys) == len(values):
                dockwidget.getMirror().overrides = dict(zip(keys, values))
                dockwidget.getMirror().updateStyleOverrides()
            
            self.addDockWidget( dockwidget )
            dockwidget.setMinimumSize(minsize)
            dockwidget.setMaximumSize(maxsize)
    
    