"""@package OsmCreatePointMT
This module holds all structures and methods required to perform
"create point" operation on current OSM data.

Snapping to existing segments of lines/polygons is supported when creating new point.

Process generates vertexMarkers so that user can watch results
of the operation on the map in a nice way.

There is also an interaction with plugin's "OSM Feature" dockwidget.
New points are loaded to it dynamically.
"""


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

import sqlite3
from math import *



class OsmCreatePointMT(QgsMapTool):
    """This class holds all structures and methods required to perform
    "create point" operation on current OSM data.

    Snapping to existing segments of lines/polygons is supported when creating new point.

    Process generates vertexMarkers so that user can watch results
    of the operation on the map in a nice way.

    There is also an interaction with plugin's "OSM Feature" dock widget.
    New points are loaded to it dynamically.
    """


    def __init__(self,plugin):
        """The constructor.

        Initializes the map tool, creates necessary snappers.

        @param plugin pointer to OSM Plugin instance
        """

        QgsMapTool.__init__(self,plugin.canvas)
        self.canvas=plugin.canvas
        self.dockWidget=plugin.dockWidget
        self.dbm=plugin.dbm
        self.ur=plugin.undoredo
        self.snappingEnabled=True
        self.snapFeat=None
        self.snapFeatType=None

        # creating vertex marker
        self.verMarker=self.createVertexMarker()

        # creating snapper to this map tool
        self.snapper=self.createSnapper(self.canvas.mapRenderer())


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

        Function does re-initialization of maptool and create new snapper again (if necessary).

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

        # re-initialization
        self.snappingEnabled=True
        self.snapFeat=None
        self.snapFeatType=None
        self.verMarker.setCenter(QgsPoint(-1000,-1000))
        self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("")

        if self.verMarker:
            self.canvas.scene().removeItem(self.verMarker)
            del self.verMarker
            self.verMarker=None

        if not dbKey:
            return

        self.verMarker=self.createVertexMarker()
        del self.snapper
        self.snapper=self.createSnapper(self.canvas.mapRenderer())


    def createVertexMarker(self):
        """Function creates vertexMarker that is used for marking new point on map.

        @return vertex marker - QgsVertexMarker object
        """

        # get qgis settings
        settings=QSettings()
        qgsLineWidth=2 # use fixed width
        qgsLineRed=settings.value("/qgis/digitizing/line_color_red",QVariant(255)).toInt()
        qgsLineGreen=settings.value("/qgis/digitizing/line_color_green",QVariant(0)).toInt()
        qgsLineBlue=settings.value("/qgis/digitizing/line_color_blue",QVariant(0)).toInt()

        verMarker=QgsVertexMarker(self.canvas)
        verMarker.setIconType(2)
        verMarker.setIconSize(13)
        verMarker.setColor(QColor(qgsLineRed[0],qgsLineGreen[0],qgsLineBlue[0]))
        verMarker.setPenWidth(qgsLineWidth)
        verMarker.setCenter(QgsPoint(-1000,-1000))

        return verMarker


    def createSnapper(self,canvasRenderer):
        """Function creates snapper that snaps within standard qgis tolerance.

        Snapping is done to all segments of both line and polygon layer.

        @param canvasRenderer renderer of current map canvas
        @return instance of segment QgsSnapper
        """

        if not self.dbm.currentKey:
            # there is no current database -> no layer for snapping
            return QgsSnapper(self.canvas.mapRenderer())

        snapper=QgsSnapper(self.canvas.mapRenderer())
        snapLayers=[]

        # snap to line and polygon layer from current database only
        sLayer=QgsSnapper.SnapLayer()
        sLayer.mLayer=self.dbm.lineLayers[self.dbm.currentKey]
        sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
        sLayer.mSnapTo=QgsSnapper.SnapToSegment
        snapLayers.append(sLayer)

        sLayer=QgsSnapper.SnapLayer()
        sLayer.mLayer=self.dbm.polygonLayers[self.dbm.currentKey]
        sLayer.mTolerance=QgsTolerance.vertexSearchRadius(sLayer.mLayer,self.canvas.mapRenderer())
        sLayer.mSnapTo=QgsSnapper.SnapToSegment
        snapLayers.append(sLayer)

        snapper.setSnapLayers(snapLayers)
        return snapper


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

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

        self.dockWidget.toolButtons.setExclusive(False)
        self.dockWidget.createPointButton.setChecked(False)
        self.dockWidget.toolButtons.setExclusive(True)
        self.dockWidget.activeEditButton=self.dockWidget.dummyButton

        if self.verMarker:
            self.verMarker.setCenter(QgsPoint(-1000,-1000))
            self.canvas.scene().removeItem(self.verMarker)
            del self.verMarker
            self.verMarker=None

        self.dockWidget.clear()


    def keyPressEvent(self, event):
        """This function is called after keyPressEvent(QKeyEvent *) signal
        is emmited when using this map tool.

        If Control key was pressed, function disables snapping til key is released again.

        @param event event that occured when key pressing
        """

        if (event.key()==Qt.Key_Control):
            self.snappingEnabled=False
            if self.verMarker:
                self.verMarker.setCenter(QgsPoint(-1000,-1000))
            self.snappedPoint=None
            self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping OFF.")


    def keyReleaseEvent(self, event):
        """This function is called after keyReleaseEvent(QKeyEvent *) signal
        is emmited when using this map tool.

        If Control key was released, function enables snapping again.

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

        if (event.key()==Qt.Key_Control):
            self.snappingEnabled=True
            self.dockWidget.plugin.iface.mainWindow().statusBar().showMessage("Snapping ON. Hold Ctrl to disable it.")


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

        If left button is released new point is created.
        Right (and other) clicking does nothing.

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

        if event.button()<>Qt.LeftButton:
            return    # nothing to do

        if not self.snappedPoint:
            newPoint = self.dockWidget.canvasToOsmCoords(event.pos())
        else:
            newPoint=self.snappedPoint

        self.ur.startAction("Create a point.")
        (node,affected)=self.dbm.createPoint(newPoint,self.snapFeat,self.snapFeatType)
        self.ur.stopAction(affected)
        self.dbm.recacheAffectedNow(affected)

        if node:
            self.dockWidget.loadFeature(node,"Point",2)

        self.canvas.refresh()


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

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

        self.mapPoint = self.dockWidget.canvasToOsmCoords(event.pos())

        # try snapping to the closest vertex/segment
        if not self.snappingEnabled:
            self.verMarker.setCenter(self.mapPoint)
            return

        # snapping! first reset old snapping vertexMarker
        self.verMarker.setCenter(QgsPoint(-1000,-1000))

        (retval,snappingResults)=self.snapper.snapPoint(event.pos(),[])

        if len(snappingResults)==0:
            self.verMarker.setCenter(self.mapPoint)
            self.snappedPoint=None
            self.snapFeat=None
            self.snapFeatType=None

            if self.dockWidget.feature:
                self.dockWidget.clear()
            return

        self.snappedPoint=QgsPoint(snappingResults[0].snappedVertex)
        self.verMarker.setCenter(self.snappedPoint)

        # start identification
        feature=self.dbm.findFeature(self.snappedPoint)
        if feature:
            (self.snapFeat,self.snapFeatType)=feature
            if not self.dockWidget.feature or self.snapFeat.id()<>self.dockWidget.feature.id():
                self.dockWidget.loadFeature(self.snapFeat,self.snapFeatType)



