# -*- coding: utf-8 -*-

#-----------------------------------------------------------
#
# fTools
# Copyright (C) 2008-2011  Carson Farmer
# EMAIL: carson.farmer (at) gmail.com
# WEB  : http://www.ftools.ca/fTools.html
#
# A collection of data management and analysis tools for vector data
#
#-----------------------------------------------------------
#
# licensed under the terms of GNU GPL 2
#
# 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.
#
# This program 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 General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#---------------------------------------------------------------------

# Utility functions
# -------------------------------------------------
#
# convertFieldNameType( QgsField.name() )
# combineVectorFields( QgsVectorLayer, QgsVectorLayer )
# checkCRSCompatibility( QgsCoordinateReferenceSystem, QgsCoordinateReferenceSystem )
# writeVectorLayerToShape(QgsVectorLayer, QString *file path, QString *encoding style )
# getVectorTypeAsString( QgsVectorLayer )
# measurePerimeter( QgsGeometry )
# extractPoints( QgsGeometry )
# testForUniqueness( QList *QgsField, QList *QgsField )
# createUniqueFieldName( QgsField.name() )
# checkFieldNameLength( QgsFieldMap )
# getLayerNames( QGis.vectorType() )
# getFieldNames( QgsVectorLayer )
# getVectorLayerByName( QgsVectorLayer.name() )
# getFieldList( QgsVectorLayer )
# createIndex( QgsVectorDataProvider )
# addShapeToCanvas( QString *file path )
# getUniqueValues( QgsVectorDataProvider, int *field id )
# saveDialog( QWidget *parent )
# getFieldType( QgsVectorLayer, QgsField.name() )
# getUniqueValuesCount( QgsVectorLayer, int fieldIndex, bool useSelection ):
#
# -------------------------------------------------

from PyQt4.QtCore import QTextCodec, QFileInfo, QSettings, QCoreApplication
from PyQt4.QtGui import QDialog, QFileDialog
from qgis.core import QgsVectorFileWriter, QGis, QgsDistanceArea, QgsGeometry, QgsMapLayer, QgsVectorLayer, QgsMapLayerRegistry, QgsFeature, QgsSpatialIndex
from qgis.gui import QgsEncodingFileDialog

import locale

# For use with memory provider/layer, converts full field type to simple string


def convertFieldNameType(inName):
    if inName == "Integer":
        return "int"
    elif inName == "Real":
        return "double"
    else:
        return "string"

# From two input field maps, create single field map


def combineVectorFields(layerA, layerB):
    fieldsA = layerA.dataProvider().fields()
    fieldsB = layerB.dataProvider().fields()
    fieldsB = testForUniqueness(fieldsA, fieldsB)
    for f in fieldsB:
        fieldsA.append(f)
    return fieldsA

# Check if two input CRSs are identical


def checkCRSCompatibility(crsA, crsB):
    if crsA == crsB:
        return True
    else:
        return False

# Convenience function to write vector layer to shapefile


def writeVectorLayerToShape(vlayer, outputPath, encoding):
    mCodec = QTextCodec.codecForName(encoding)
    if not mCodec:
        return False
    #Here we should check that the output path is valid
    QgsVectorFileWriter.writeAsVectorFormat(vlayer, outputPath, encoding, vlayer.dataProvider().crs(), "ESRI Shapefile", False)
    return True

# For use with memory provider/layer, converts QGis vector type definition to simple string


def getVectorTypeAsString(vlayer):
    if vlayer.geometryType() == QGis.Polygon:
        return "Polygon"
    elif vlayer.geometryType() == QGis.Line:
        return "LineString"
    elif vlayer.geometryType() == QGis.Point:
        return "Point"
    else:
        return False

# Compute area and perimeter of input polygon geometry


def getAreaAndPerimeter(geom):
    measure = QgsDistanceArea()
    area = measure.measure(geom)
    perim = measurePerimeter(geom, measure)
    return (area, perim)

# Compute perimeter of input polygon geometry


def measurePerimeter(geom):
    measure = QgsDistanceArea()
    value = 0.00
    polygon = geom.asPolygon()
    for line in polygon:
        value += measure.measureLine(line)
    return value

# Generate list of QgsPoints from input geometry ( can be point, line, or polygon )


def extractPoints(geom):
    multi_geom = QgsGeometry()
    temp_geom = []
    if geom.type() == 0: # it's a point
        if geom.isMultipart():
            temp_geom = geom.asMultiPoint()
        else:
            temp_geom.append(geom.asPoint())
    elif geom.type() == 1: # it's a line
        if geom.isMultipart():
            multi_geom = geom.asMultiPolyline()  # multi_geog is a multiline
            for i in multi_geom:  # i is a line
                temp_geom.extend(i)
        else:
            temp_geom = geom.asPolyline()
    elif geom.type() == 2: # it's a polygon
        if geom.isMultipart():
            multi_geom = geom.asMultiPolygon()  # multi_geom is a multipolygon
            for i in multi_geom:  # i is a polygon
                for j in i:  # j is a line
                    temp_geom.extend(j)
        else:
            multi_geom = geom.asPolygon()  # multi_geom is a polygon
            for i in multi_geom:  # i is a line
                temp_geom.extend(i)
    # FIXME - if there is none of know geoms (point, line, polygon) show an warning message
    return temp_geom

# Check if two input field maps are unique, and resolve name issues if they aren't


def testForUniqueness(fieldList1, fieldList2):
    changed = True
    while changed:
        changed = False
        for i in range(0, len(fieldList1)):
            for j in range(0, len(fieldList2)):
                if fieldList1[i].name() == fieldList2[j].name():
                    fieldList2[j] = createUniqueFieldName(fieldList2[j])
                    changed = True
    return fieldList2

# Create a unique field name based on input field name


def createUniqueFieldName(field):
    check = field.name()[-2:]
    shortName = field.name()[:8]
    if check[0] == "_":
        try:
            val = int(check[-1:])
            if val < 2:
                val = 2
            else:
                val = val + 1
            field.setName(shortName[:-1] + unicode(val))
        except ValueError:
            field.setName(shortName + "_2")
    else:
        field.setName(shortName + "_2")
    return field

# Return list of field names with more than 10 characters length


def checkFieldNameLength(fieldList):
    longNames = []
    for field in fieldList:
        if len(field.name()) > 10:
            longNames.append(field.name())
    return longNames

# Return list of names of all layers in QgsMapLayerRegistry


def getLayerNames(vTypes):
    layermap = QgsMapLayerRegistry.instance().mapLayers()
    layerlist = []
    if vTypes == "all":
        for name, layer in layermap.iteritems():
            layerlist.append(layer.name())
    else:
        for name, layer in layermap.iteritems():
            if layer.type() == QgsMapLayer.VectorLayer:
                if layer.geometryType() in vTypes:
                    layerlist.append(layer.name())
            elif layer.type() == QgsMapLayer.RasterLayer:
                if "Raster" in vTypes:
                    layerlist.append(layer.name())
    return sorted(layerlist, cmp=locale.strcoll)

# Return list of names of all fields from input QgsVectorLayer


def getFieldNames(vlayer):
    fieldmap = getFieldList(vlayer)
    fieldlist = []
    for field in fieldmap:
        if not field.name() in fieldlist:
            fieldlist.append(field.name())
    return sorted(fieldlist, cmp=locale.strcoll)

# Return QgsVectorLayer from a layer name ( as string )


def getVectorLayerByName(myName):
    layermap = QgsMapLayerRegistry.instance().mapLayers()
    for name, layer in layermap.iteritems():
        if layer.type() == QgsMapLayer.VectorLayer and layer.name() == myName:
            if layer.isValid():
                return layer
            else:
                return None

# Return QgsRasterLayer from a layer name ( as string )


def getRasterLayerByName(myName):
    layermap = QgsMapLayerRegistry.instance().mapLayers()
    for name, layer in layermap.iteritems():
        if layer.type() == QgsMapLayer.RasterLayer and layer.name() == myName:
            if layer.isValid():
                return layer
            else:
                return None

# Return QgsMapLayer from a layer name ( as string )


def getMapLayerByName(myName):
    layermap = QgsMapLayerRegistry.instance().mapLayers()
    for name, layer in layermap.iteritems():
        if layer.name() == myName:
            if layer.isValid():
                return layer
            else:
                return None

# Return the field list of a vector layer


def getFieldList(vlayer):
    return vlayer.dataProvider().fields()

# Convinience function to create a spatial index for input QgsVectorDataProvider


def createIndex(provider):
    feat = QgsFeature()
    index = QgsSpatialIndex()
    fit = provider.getFeatures()
    while fit.nextFeature(feat):
        index.insertFeature(feat)
    return index

# Convinience function to add a vector layer to canvas based on input shapefile path ( as string )


def addShapeToCanvas(shapefile_path):
    file_info = QFileInfo(shapefile_path)
    if file_info.exists():
        layer_name = file_info.completeBaseName()
    else:
        return False
    vlayer_new = QgsVectorLayer(shapefile_path, layer_name, "ogr")
    if vlayer_new.isValid():
        QgsMapLayerRegistry.instance().addMapLayers([vlayer_new])
        return True
    else:
        return False

# Return all unique values in field based on field index


def getUniqueValues(provider, index):
    return provider.uniqueValues(index)

# Generate a save file dialog with a dropdown box for choosing encoding style


def saveDialog(parent, filtering="Shapefiles (*.shp *.SHP)"):
    settings = QSettings()
    dirName = settings.value("/UI/lastShapefileDir")
    encode = settings.value("/UI/encoding")
    fileDialog = QgsEncodingFileDialog(parent, QCoreApplication.translate("fTools", "Save output shapefile"), dirName, filtering, encode)
    fileDialog.setDefaultSuffix("shp")
    fileDialog.setFileMode(QFileDialog.AnyFile)
    fileDialog.setAcceptMode(QFileDialog.AcceptSave)
    fileDialog.setConfirmOverwrite(True)
    if not fileDialog.exec_() == QDialog.Accepted:
        return None, None
    files = fileDialog.selectedFiles()
    settings.setValue("/UI/lastShapefileDir", QFileInfo(unicode(files[0])).absolutePath())
    return (unicode(files[0]), unicode(fileDialog.encoding()))

# Generate a save file dialog with a dropdown box for choosing encoding style
# with mode="SingleFile" will allow to select only one file, in other cases - several files


def openDialog(parent, filtering="Shapefiles (*.shp *.SHP)", dialogMode="SingleFile"):
    settings = QSettings()
    dirName = settings.value("/UI/lastShapefileDir")
    encode = settings.value("/UI/encoding")
    fileDialog = QgsEncodingFileDialog(
        parent,
        QCoreApplication.translate("fTools", "Select input file")
        if dialogMode == "SingleFile" else
        QCoreApplication.translate("fTools", "Select input files"),
        dirName, filtering, encode)
    fileDialog.setFileMode(QFileDialog.ExistingFiles)
    fileDialog.setAcceptMode(QFileDialog.AcceptOpen)
    if not fileDialog.exec_() == QDialog.Accepted:
        return None, None
    files = fileDialog.selectedFiles()
    settings.setValue("/UI/lastShapefileDir", QFileInfo(unicode(files[0])).absolutePath())
    if dialogMode == "SingleFile":
        return (unicode(files[0]), unicode(fileDialog.encoding()))
    else:
        return (files, unicode(fileDialog.encoding()))

# Generate a select directory dialog with a dropdown box for choosing encoding style


def dirDialog(parent):
    settings = QSettings()
    dirName = settings.value("/UI/lastShapefileDir")
    encode = settings.value("/UI/encoding")
    fileDialog = QgsEncodingFileDialog(parent, QCoreApplication.translate("fTools", "Save output directory"), dirName, encode)
    fileDialog.setFileMode(QFileDialog.DirectoryOnly)
    fileDialog.setAcceptMode(QFileDialog.AcceptSave)
    fileDialog.setConfirmOverwrite(False)
    if not fileDialog.exec_() == QDialog.Accepted:
        return None, None
    folders = fileDialog.selectedFiles()
    settings.setValue("/UI/lastShapefileDir", QFileInfo(unicode(folders[0])).absolutePath())
    return (unicode(folders[0]), unicode(fileDialog.encoding()))

# Return field type from it's name


def getFieldType(vlayer, fieldName):
    for field in vlayer.dataProvider().fields():
        if field.name() == fieldName:
            return field.typeName()

# return the number of unique values in field


def getUniqueValuesCount(vlayer, fieldIndex, useSelection):
    count = 0
    values = []
    if useSelection:
        selection = vlayer.selectedFeatures()
        for f in selection:
            v = f.attributes()[fieldIndex]
            if v not in values:
                values.append(v)
                count += 1
    else:
        feat = QgsFeature()
        fit = vlayer.dataProvider().getFeatures()
        while fit.nextFeature(feat):
            v = feat.attributes()[fieldIndex]
            if v not in values:
                values.append(v)
                count += 1
    return count


def getGeomType(gT):
    if gT == 3 or gT == 6:
        gTypeListPoly = [QGis.WKBPolygon, QGis.WKBMultiPolygon]
        return gTypeListPoly
    elif gT == 2 or gT == 5:
        gTypeListLine = [QGis.WKBLineString, QGis.WKBMultiLineString]
        return gTypeListLine
    elif gT == 1 or gT == 4:
        gTypeListPoint = [QGis.WKBPoint, QGis.WKBMultiPoint]
        return gTypeListPoint


def getShapesByGeometryType(baseDir, inShapes, geomType):
    outShapes = []
    for fileName in inShapes:
        layerPath = QFileInfo(baseDir + "/" + fileName).absoluteFilePath()
        vLayer = QgsVectorLayer(layerPath, QFileInfo(layerPath).baseName(), "ogr")
        if not vLayer.isValid():
            continue
        layerGeometry = vLayer.geometryType()
        if layerGeometry == QGis.Polygon and geomType == 0:
            outShapes.append(fileName)
        elif layerGeometry == QGis.Line and geomType == 1:
            outShapes.append(fileName)
        elif layerGeometry == QGis.Point and geomType == 2:
            outShapes.append(fileName)

    if len(outShapes) == 0:
        return None

    return outShapes


def getShapefileName(outPath, extension='.shp'):
    import os.path
    outName = os.path.basename(outPath)
    if outName.endswith(extension):
        outName = outName[:-len(extension)]
    return outName
