#coding=utf-8
#Copyright (C) 2015 IDAEA-CSIC
#
#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 
#ITHOUT 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
'''
:copyright: Copyright (C) 2015 IDAEA-CSIC
:authors: V. Velasco Mansilla, L.M. de Vries, A. Nardi, R. Criollo, E. Vázquez Suñé
:contact: enric.vazquez@idaea.csic.es
:license: GPL General Public License, version 2 or any later version (http://opensource.org/licenses/GPL-2.0)
'''
from qgis.core import QgsDataSourceURI, QgsVectorLayer, QgsMapLayerRegistry, QgsProject
from PyQt4.QtGui import QIcon, QFileDialog 
from PyQt4.Qt import QMessageBox
import os, shutil

from form.AKFormCreateDB import AKFormCreateDB    
from AKFeature import AKFeature
from AKSettings import TABLES

class AKFeatureCreateDB (AKFeature):
    ''' 
    This feature takes care of creating and loading AkvaGIS databases. When a database is loaded, all the relevant 
    tables are exposed to QGIS by adding layers.
    '''
    def __init__(self, settings, iface, dialogType, toolbarActions, parent=None):
        super(AKFeatureCreateDB, self).__init__(iface, parent)
        
        self.m_settings = settings
        self.m_form = AKFormCreateDB(self.iface)
        self.dialogType = dialogType
        self.m_actions = toolbarActions
                
        if(dialogType == "create"):
            self.m_icon = QIcon(settings.getIconPath('document-new.png'))
            self.m_text = "Create AkvaGIS Database"
            proposedFileName =  os.path.join(os.path.expanduser("~"),"yourDB.sql")  
            self.m_form.txtDBFilePath.setText(proposedFileName)

        elif(dialogType == "open"):
            self.m_icon = QIcon(settings.getIconPath('document-open.png'))
            self.m_text = "Open AkvaGIS Database"
            self.m_form.btnCreate.setText("Open")
            lastOpenedFileName = self.m_settings.getUserSettings("lastDBOpened")
            if lastOpenedFileName == "":
                currentDir = os.path.normpath(os.path.dirname(os.path.realpath(__file__)))
                lastOpenedFileName = os.path.normpath(os.path.join(currentDir,  "../testData/akvaGIS.sqlite"))
            self.m_form.txtDBFilePath.setText(lastOpenedFileName)
        self.m_form.setWindowTitle(self.m_text)
        
        self.m_group = "AkvaGIS"
        
        if(self.dialogType == "create"):
            self.m_form.btnCreate.clicked.connect(self.onCreate)
        if(self.dialogType == "open"):
            self.m_form.btnCreate.clicked.connect(self.onOpen)
        
        self.m_form.btnBrowse.clicked.connect(self.onBrowse)
        self.m_form.txtGroup.setText(self.m_group)
        self.m_form.finished.connect(self.onClose)

    def initialize(self):
        self.m_form.show()
        self.m_form.exec_()
        
    def onBrowse(self):
        fileName = ""
        curDir = os.path.dirname(self.m_form.txtDBFilePath.text())
        if(self.dialogType == "open"):
            fileName = QFileDialog.getOpenFileName(self.m_form, "Open AkvaGIS database", curDir, "database files (*.sqlite)")
        elif(self.dialogType == "create"):
            fileName = QFileDialog.getSaveFileName(self.m_form, "Create AkvaGIS database", curDir, "database files (*.sqlite)")
        if fileName != "": 
            self.m_form.txtDBFilePath.setText(fileName)

    def onCreate(self):
        if(self.m_settings.currentDB != None):
            ret = self.confirmClosing()
            if ret == QMessageBox.Yes:
                self.closeDatabase()
            else:
                self.onClose()
                return
        
        filePath = self.m_form.txtDBFilePath.text()
        if os.path.isfile(filePath):
            ret = self.confirmReplacement()
            if ret == QMessageBox.No:
                self.onClose()
                return
                
        emptyDB = os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + "/../db/initialAkvaGIS.sqlite")
        if os.path.isfile(emptyDB):
            shutil.copyfile(emptyDB, os.path.normpath(filePath)) 
            error = self.m_settings.openCurrentDB(filePath)
            if not error:
                self.createLayers()
                self.updateButtons()
                self.onClose()
                self.m_settings.setUserSettings("lastDBOpened", filePath)
        else:
            QMessageBox.warning(self.m_form,
                        "Warning",
                        "Cannot find empty database template: " + emptyDB)

    def onOpen(self):
        filePath = os.path.normpath(self.m_form.txtDBFilePath.text())
        if(self.m_settings.currentDB != None):
            pointsLayer = self.m_settings.m_availableTables[TABLES.POINTS]["layerObject"]
            currentPath = os.path.normpath(self.m_settings.getLayerDBPath(pointsLayer))
            if currentPath != filePath:
                ret = self.confirmClosing()
                if ret == QMessageBox.Yes:
                    self.closeDatabase()
                else:
                    QMessageBox.information(self.iface.mainWindow(),
                                            "Database already Open",
                                            "The requested database is already open")
                    return
            else:
                self.onClose()
                return
        isError = self.m_settings.openCurrentDB(filePath)
        if not isError:
            isAkvaGISDB = self.m_settings.verifyAkvaGISDB()
            if(isAkvaGISDB):
                self.createLayers()
                self.updateButtons()
                self.onClose()
                self.m_settings.setUserSettings("lastDBOpened", filePath)
            else:
                self.m_settings.closeCurrentDB()
                QMessageBox.warning(self.iface.mainWindow(), "Warning",
                        "The database selected is not an AkvaGIS database.")

    def createLayers(self):
        root = QgsProject.instance().layerTreeRoot()
        baseGroupName = self.generateNewName(self.m_form.txtGroup.text())
        baseGroupNode = root.addGroup(baseGroupName)
        self.m_settings.dbGroup = baseGroupName

        self.addNodes(baseGroupNode, self.m_settings.layersView)
        self.addDelegatesToLayer()
        
    def addNodes(self, parentNode, sourceItem):
        availableTables = self.m_settings.m_availableTables
        for item in sourceItem:
            if isinstance(item, tuple):
                extraGroupName = item[0]
                extraGroupNode = parentNode.addGroup(extraGroupName)
                self.addNodes(extraGroupNode,item[1])  
            else:
                newLayer = self.addLayer(parentNode, item)
                availableTables[item]["layerObject"] = newLayer
                    
    def addDelegatesToLayer(self):
        availableTables = self.m_settings.m_availableTables
        for curTable in availableTables:
            curTableInfo = availableTables[curTable]
            if("layerObject" in curTableInfo):
                curLayer = curTableInfo["layerObject"]
                if("relationalFields" in curTableInfo):
                    for relFieldInfo in curTableInfo["relationalFields"]: 
                        curLayer.setEditorWidgetV2(relFieldInfo["fieldIndex"], "ValueRelation")
                        relTableName = relFieldInfo["tableName"]
                        relTableInfo = availableTables[relTableName]
                        relLayer = relTableInfo["layerObject"]
                        relLayerId = relLayer.id()
                        curLayer.setEditorWidgetV2Config(relFieldInfo["fieldIndex"],
                                                         {"Key":  relFieldInfo["keyField"],
                                                          "Layer": relLayerId,
                                                          "Value":relFieldInfo["valueField"],
                                                          "OrderByValue": True})
                if("dateTimeFields" in curTableInfo):
                    for dateTimeInfo in curTableInfo["dateTimeFields"]:
                        curLayer.setEditorWidgetV2(dateTimeInfo["fieldIndex"], 'DateTime' )
                        curLayer.setEditorWidgetV2Config(dateTimeInfo["fieldIndex"], {'display_format': 'yyyy-MM-dd HH:mm:ss', 
                                                                                      'allow_null': False,
                                                                                      'field_format': 'yyyy-MM-dd HH:mm:ss', 
                                                                                      'calendar_popup': True})
                if("nonEditableFields" in curTableInfo):
                    for nonEditInfo in curTableInfo["nonEditableFields"]:
                        curLayer.setEditorWidgetV2(nonEditInfo["fieldIndex"], 'TextEdit' )
                        curLayer.setFieldEditable(nonEditInfo["fieldIndex"], False )
                    

    def updateButtons(self):
        if(self.m_settings.currentDB == None):
            self.enableAkvaGIS(False)
        else:
            self.enableAkvaGIS(True)
            
    def enableAkvaGIS(self, setEnabled):
        for action in self.m_actions:
            if(action.text() != self.m_text):
                action.setEnabled(setEnabled)

    def addLayer(self, parentNode, tableName):
        availableTables = self.m_settings.m_availableTables
        layerName = tableName
        geometryColumn = ""
        if("tableName" in availableTables[tableName]):
            tableName = availableTables[tableName]["tableName"]
        if("layerName" in availableTables[tableName]):
            layerName = availableTables[tableName]["layerName"]
        if("geometryColumn" in availableTables[tableName]):
            geometryColumn = availableTables[tableName]["geometryColumn"]
        newLayer = self.addDBTableAsLayer(parentNode, layerName, tableName, geometryColumn)
        if(layerName == TABLES.POINTS):
            newLayer.setCustomProperty("labeling", "pal")
            newLayer.setCustomProperty("labeling/enabled", "true")
            newLayer.setCustomProperty("labeling/fieldName", "point")
            newLayer.setCustomProperty("labeling/fontFamily", "Arial")
            newLayer.setCustomProperty("labeling/fontSize", "10")
            newLayer.setCustomProperty("labeling/dist", "0.4")
        return newLayer

    def addDBTableAsLayer(self, groupNode, layerName, tableName, geometryColumn):
        uri = QgsDataSourceURI()
        uri.setDatabase(self.m_settings.currentDB.connectionName())
        schema = ''
        table = tableName
        geom_column = geometryColumn
        uri.setDataSource(schema, table, geom_column)         
        display_name = layerName
        newLayer = QgsVectorLayer(uri.uri(), display_name, 'spatialite')
        QgsMapLayerRegistry.instance().addMapLayer(newLayer, False)
        groupNode.addLayer(newLayer)
        return newLayer
        
    def onClose(self):
        self.m_form.accept()
