"""@package OsmIdentifyMT
This module holds all structures and methods required to perform
"identify feature" operation on current OSM data.

When feature is identified its id, type, timestamp, owner, properties/tags, relations are loaded
into OSM Feature widget. Feature is also marked with rubberband (or vertexmarker for points) on map.

If you want to identify some feature, just left-click on it.

If OSM Plugin marked wrong feature after that, repeat RIGHT-clicking til the right one is marked.
(Right-clicking gives you one by one each feature that is in the place where left-click was done.)

If no feature is marked after your left-clicking, you missed the feature :-) Try again.

If you are not able to hit any feature, be sure that map data you are trying to identify are the current OSM data.

If they are, maybe there is something wrong in your QGIS settings. Be sure that there aren't too small values
in QGIS Settings -> Digitalization -> Tolerance/Snapping.

If you've just identified the wrong feature or want to identify a new one,
just left-click to continue the identification process.
"""


from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from qgis.gui import *


class OsmIdentifyMT(QgsMapTool):
    """This class holds all structures and methods required to perform
    "identify feature" operation on current OSM data.

    When feature is identified its id, type, timestamp, owner, properties/tags, relations are loaded
    into OSM Feature widget. Feature is also marked with rubberband (or vertexmarker for points) on map.

    If you want to identify some feature, just left-click on it.

    If OSM Plugin marked wrong feature after that, repeat RIGHT-clicking til the right one is marked.
    (Right-clicking gives you one by one each feature that is in the place where left-click was done.)

    If no feature is marked after your left-clicking, you missed the feature :-) Try again.

    If you are not able to hit any feature, be sure that map data you are trying to identify are the current OSM data.

    If they are, maybe there is something wrong in your QGIS settings. Be sure that there aren't too small values
    in QGIS Settings -> Digitalization -> Tolerance/Snapping.

    If you've just identified the wrong feature or want to identify a new one,
    just left-click to continue the identification process.
    """


    def __init__(self, canvas, dockWidget, dbManager):
        """The constructor.
        Initializes the map tool.

        @param canvas map canvas
        @param dockWidget pointer to the main widget (OSM Feature widget) of OSM Plugin
        @param dbManager pointer to instance of OsmDatabaseManager; for communication with sqlite3 database
        """

        QgsMapTool.__init__(self,canvas)

        self.canvas=canvas
        self.dockWidget=dockWidget
        self.dbm=dbManager
        self.moves=0
        self.pause=False
        self.doubleclick=False
        self.featuresFound=[]
        self.ixFeature=0

        self.dlgSelect=QDialog(self.dockWidget)
        self.dlgSelect.setWindowTitle("Feature identification")
        butBox=QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel,Qt.Horizontal,self.dlgSelect)

        self.lw=QListWidget(self.dlgSelect)

        layout=QVBoxLayout(self.dlgSelect)
        layout.addWidget(self.lw)
        layout.addWidget(butBox)
        self.dlgSelect.setLayout(layout)

        QObject.connect(butBox,SIGNAL("accepted()"),self.onSelectDlgOK)
        QObject.connect(butBox,SIGNAL("rejected()"),self.onSelectDlgCancel)

        self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")


    def databaseChanged(self,dbKey):
        """This function is called automatically when current OSM database has changed.

        Function does re-initialization of maptool.

        @param dbKey key of database with new current OSM data
        """

        # re-initialization
        self.pause=False
        self.doubleclick=False
        self.featuresFound=[]
        self.ixFeature=0

        self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")


    def canvasDoubleClickEvent(self,event):
        """This function is called after doubleclick is done on map when using this map tool.
        Function is interested into left-doubleclicking only.

        It finds out all features that are currently at the place where doubleclick was done.
        Then it shows simple dialog with the list of all these features. User can select the required one
        and close dialog.

        Selected feature is then loaded into OSM Feature widget.

        @param event event that occured when double clicking
        """

        if event.button()<>Qt.LeftButton:
            return

        self.dockWidget.clear()

        # find out map coordinates from mouse click
        mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())

        # display modal dialog with features selection
        self.featuresFound=self.dbm.findAllFeatures(mapPoint)
        self.ixFeature=0

        lwItems=[]
        for f in self.featuresFound:
            feat=f[0]
            featType=f[1]
            name=self.dbm.getTagValue(feat.id(),featType,"name")
            lwItems.append(QString("[%1] ").arg(feat.id()).append(featType).append(QString(" ")).append(name))

        self.lw.clear()
        self.lw.addItems(lwItems)

        self.pause=False
        self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
        self.doubleclick=True

        # continue only if OK button was clicked
        if self.dlgSelect.exec_()==0:
            return


    def canvasReleaseEvent(self,event):
        """This function is called after mouse button is released on map when using this map tool.

        It finds out all features that are currently at place where releasing was done.

        OSM Plugin then marks the first of them. User can repeat right-clicking to mark
        the next one, the next one, the next one... periodically...
        Note that only one feature is marked at a time.

        Each marked feature is also loaded into OSM Feature widget.

        @param event event that occured when button releasing
        """

        if self.doubleclick:
            self.doubleclick=False
            return

        # we are interested only in left/right button clicking
        if event.button() not in (Qt.LeftButton,Qt.RightButton):
            return

        # find out map coordinates from mouse click
        mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())

        if event.button()==Qt.LeftButton:

            if self.pause:
                self.pause=False
                self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")
                self.featuresFound=[]
                self.ixFeature=0
                return

            # start identification
            self.featuresFound=self.dbm.findAllFeatures(mapPoint)
            self.ixFeature=0

            if len(self.featuresFound)>0:

                self.pause=True
                self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("PAUSED. Left-click to continue.")

                (feat,featType)=self.featuresFound[self.ixFeature]

                self.dockWidget.loadFeature(feat,featType,2)

            elif self.dockWidget.feature:
                self.dockWidget.clear()

        elif event.button()==Qt.RightButton:

            if len(self.featuresFound)<1:
                return

            self.ixFeature=self.ixFeature+1
            if self.ixFeature>=len(self.featuresFound):
                self.ixFeature=0

            (feat,featType)=self.featuresFound[self.ixFeature]
            self.dockWidget.loadFeature(feat,featType,2)


    def canvasMoveEvent(self,event):
        """This function is called after mouse moving.

        Feature are marked and loaded dynamically when going over them.

        @param event event that occured when mouse moving.
        """

        if self.pause:
            return

        if self.moves<>1:
            self.moves=self.moves+1
            return

        self.moves=0

        # find out map coordinates from mouse click
        mapPoint=self.dockWidget.canvasToOsmCoords(event.pos())

        # start identification
        feature=self.dbm.findFeature(mapPoint)

        if feature:
            (feat,featType)=feature

            if not self.dockWidget.feature or feat.id()<>self.dockWidget.feature.id():
                self.dockWidget.loadFeature(feat,featType,1)

        elif self.dockWidget.feature:

            self.dockWidget.clear()


    def onSelectDlgOK(self):
        """This function handles clicking on OK button of selection dialog.
        """

        self.dlgSelect.close()

        if not self.lw.currentItem():
            return

        self.ixFeature=self.lw.currentRow()
        (feat,featType)=self.featuresFound[self.ixFeature]

        if feat:
            self.dockWidget.loadFeature(feat,featType,2)
            self.pause=True


    def onSelectDlgCancel(self):
        """This function handles clicking on Cancel button of selection dialog.
        """

        self.dlgSelect.close()


    def deactivate(self):
        """Functions is called when identify-map-tool is being deactivated.

        It performs standard cleaning;
        re-initialization etc.
        """

        self.dockWidget.toolButtons.setExclusive(False)
        self.dockWidget.identifyButton.setChecked(False)
        self.dockWidget.toolButtons.setExclusive(True)
        self.dockWidget.activeEditButton=self.dockWidget.dummyButton
        self.pause=False
        self.doubleclick=False

        self.dockWidget.clear()
        self.featuresFound=[]
        self.ixFeature=0