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

#******************************************************************************
#
# Freewat
# ---------------------------------------------------------
#
#
# Copyright (C) 2014 - 2015 Iacopo Borsi (iacopo.borsi@tea-group.com)
#
# This source 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 code 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.
#
# A copy of the GNU General Public License is available on the World Wide Web
# at <http://www.gnu.org/licenses/>. You can also obtain it by writing
# to the Free Software Foundation, 51 Franklin Street, Suite 500 Boston,
# MA 02110-1335 USA.
#
#******************************************************************************
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
import os
from PyQt4 import QtGui, uic
from freewat.freewat_utils import getVectorLayerByName, getVectorLayerNames, getModelsInfoLists, getModelInfoByName, getTransportModelsByName, fileDialog, getFieldNames, load_table, read_data, pop_message
from datetime import datetime, timedelta, date
from freewat.sqlite_utils import getTableNamesList, uploadQgisTableLayer, uploadQgisVectorLayer
from pyspatialite import dbapi2 as sqlite3
from collections import defaultdict, OrderedDict
import freewat.createGrid_utils
import numpy as np
from freewat.crop_utils import CropGrowthModule
import matplotlib.pyplot as pl

#
class createCropDialog(QDialog):
    def __init__(self, iface):
        QDialog.__init__(self)
        self.iface = iface
        uic.loadUi(os.path.join( os.path.dirname(__file__), 'ui/ui_createCrop.ui'), self)
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.createCrop)
        self.updateButton.clicked.connect(self.updateTable)
        self.manageGui()

    def manageGui(self):
        self.cmbModelName.clear()
        layerNameList = getVectorLayerNames()
        (self.modelNameList, self.working_dir) =  getModelsInfoLists(layerNameList)

        self.cmbModelName.addItems(self.modelNameList)
        self.modelName = self.cmbModelName.currentText()

        # Infor of the model
        (self.pathfile, nsp ) = getModelInfoByName(self.modelName)
        self.dbName = os.path.join(self.pathfile, self.modelName + '.sqlite')
        self.tableList = getTableNamesList(self.dbName)
        self.modeltable = getVectorLayerByName( 'modeltable_' + self.modelName)


        # fill the combobox with just the Crop table of the database
        crp = []
        for i in layerNameList:
            if 'CropsTable' in i:
                crp.append(i)
        # filter the crop table combobox with only the Crop Table (table)
        self.cmbCrop.addItems(crp)


        # # for the future, set the initial ts date from the model like that
        # for i in self.modeltable.getFeatures():
        #     init_date = i['initial_date']
        # date0 = datetime.strptime(init_date, "%Y-%m-%d")
        # date0 = date0.date()
        #
        # self.dateEdit_ts.setDate(date0)


    def updateTable(self):
        '''
        update the QTableWidget with the fields of the layer selected in the combobox
        '''
        # get the crop table from the combobox
        crop_table = self.cmbCrop.currentText()

        # get the Crop Table from the QGIS TOC as QgsVectorLayer
        vl = getVectorLayerByName(crop_table)

        # provider of the vl
        pr = vl.dataProvider()


        # create a memory layer and fill it with the filtered CropLayer (that is, only ['crop_name', 'crop_id', 'active'] fields and only where 'active' is yes)

        # empty memory layer and provider
        mem = QgsVectorLayer('Point?crs=EPSG:4326', 'memoria', 'memory')
        pr_mem = mem.dataProvider()
        # fields of the original vl trought the provider
        fld = pr.fields()


        # fields of the memory layer
        fld_mem = pr_mem.fields()

        # add the FIELDS to the memory layer with the provider and update the layer
        for i in fld:
            pr_mem.addAttributes([i])

        mem.updateFields()

        # start the editing of the memory layer to be able to add features
        ll = []
        for j in vl.getFeatures():
            fet = QgsFeature()
            fet.setAttributes(j.attributes())
            ll.append(fet)


        # send the features to the provider and commit the changes
        pr_mem.addFeatures(ll)
        mem.commitChanges()

        # create filter so that the provider has just the filtered features
        filter = "active = 'yes'"
        mem.setSubsetString(filter)

        # index of fields that will stay
        crop_name_idx = mem.fieldNameIndex('crop_name')
        crop_id_idx = mem.fieldNameIndex('crop_id')
        active_idx = mem.fieldNameIndex('active')

        # list creation with field indexes that will be delated
        fields_to_delete = [fid for fid in range(len(pr_mem.fields())) if fid != crop_name_idx and fid != crop_id_idx and fid != active_idx]

        # send to provider and update the fields
        pr_mem.deleteAttributes(fields_to_delete)
        mem.updateFields()


        # create list of the vector layer fields
        k = []
        for i in pr_mem.fields():
            k.append(i.name())

        # create list of the vector layer attributes
        v = []
        for i in pr_mem.getFeatures():
            v.append(i.attributes())


        # create OrderedDict of key = fieldname and values = attributes
        fd = OrderedDict(zip(k, map(list, zip(*v))))

        # QTableWidget settings
        # column correspond to the length of the fd.keys. Could be extended by adding values len(fd.keys()) + 2
        self.dataTable.setColumnCount(len(fd.keys())+ 9)
        # row length from the length of the values of the dictionary
        self.dataTable.setRowCount(len(fd.values()[0]))
        # column names from the dictionary keys. Could be extended by adding fd.keys() + ['one', 'two']
        self.dataTable.setHorizontalHeaderLabels(fd.keys() + ['t_base', 'lai_max', 'gdd_em', 'alpha_1', 'alpha_2', 'gdd_lai_max', 'rue', 'hi_ref', 'ky'])

        # fill the QTable with the dictionary values
        for i in range(len(fd.values())):
            for j in range(len(fd.values()[i])):
                # be aware! all values are unicode! so numbers have to be converted in a second moment
                item = QTableWidgetItem(unicode(fd.values()[i][j]))
                self.dataTable.setItem(j,i,item)


        # BE AWARE THAT THE NUMBERS OF VALUES TO ADD HAVE TO BE THE SAME AS THE COLUMNS ADDED ABOVE!!
        # besides the dictionary values, fill also the remaining columns with some default values
        for i in range(len(fd.values())):
            for j in range(len(fd.values()[i])):
                # be aware! all values are unicode! so numbers have to be converted in a second moment
                # for the moment all the additional columns have EMPTY atrtibutes
                items = [QTableWidgetItem(u'10'), QTableWidgetItem(u'2'), QTableWidgetItem(u'4'), QTableWidgetItem(u'3'), QTableWidgetItem(u'4'), QTableWidgetItem(u'2.0'), QTableWidgetItem(u'1.1'), QTableWidgetItem(u'3.2'), QTableWidgetItem(u'2.1')]
                leng = len(fd.values())
                for ii, jj in enumerate(items):
                    self.dataTable.setItem(j, leng + ii, jj)

        # set the columns width
        self.dataTable.setColumnWidth(0, 128)


    def createCrop(self):

        # LOAD TIME DATA

        # Info on initial time_unit

        # initial date of the model from the modeltable and convert it to a datetime object
        for i in self.modeltable.getFeatures():
            init_date = i['initial_date']
        date0 = datetime.strptime(init_date, "%Y-%m-%d")
        date0 = date0.date()

        # initial seeding time
        date_ts = self.dateEdit_ts.date()
        init_data_ts = date_ts.toString('yyyy-MM-dd')
        # transform the seeding date in a datetime object
        self.date_ts0 = datetime.strptime(init_data_ts, "%Y-%m-%d")
        self.date_ts0 = self.date_ts0.date()

        # initial harvest time
        date_th = self.dateEdit_th.date()
        init_data_th = date_th.toString('yyyy-MM-dd')
        # transform the harvest date in a datetime object
        self.date_th0 = datetime.strptime(init_data_th, "%Y-%m-%d")
        self.date_th0 = self.date_th0.date()


        # date calculations with the seeding, harvesting and initial datetime objects
        # difference from seeding date respect to initial date
        diff_ts = self.date_ts0 - date0
        diff_ts = diff_ts.days

        # difference from seeding date respect to initial date
        diff_th = self.date_th0 - date0
        diff_th = diff_th.days

        # total TS number (in days)
        nts = (diff_th - diff_ts) + 1


        # check if the initial date (from the model table) is smaller than the other ones
        if date0 > self.date_ts0 or date0 > self.date_th0:
            QMessageBox.warning(self, self.tr('Warning!'), self.tr('Check the input date and the intial date of the model in the modeltable'))
            return


        # throw error if the harvest time is smaller than the seeding time
        if self.date_th0 < self.date_ts0:
            QMessageBox.warning(self, self.tr('Warning!'), self.tr('Harvest time has to be AFTER seed time'))
            return


        # LOAD TABLEWIDGET DATA

        # try except if the user has not clicked the Update button
        try:
            self.table_layer = load_table(self.dataTable)
        except:
            pop_message(self.tr('It seems you have not created any table. Click the Update button'), 'critical')
            return

        # create dictionary with KEYS = crop_id and VALUES = list of the attributes
        table_layer_dic = OrderedDict()

        self.crp_name = []

        for i in self.table_layer.getFeatures():
            table_layer_dic[i] = i['crop_id']
            self.crp_name.append(i['crop_name'])

        tmp_ll = []
        for i, j in enumerate(self.table_layer.getFeatures()):
            tmp_ll.append(j.attributes()[2:])


        # create dictionary with KEYS = CROP ID and values are the list for each key
        self.table_dic = {k[0] : k[1:] for k in tmp_ll}

        # load the VectorLayer created from the QTableWiget in the DB and in the TOC
        crop_line_name = self.crop_model_name.text()
        crop__model_name = crop_line_name + '_cgm'
        uploadQgisVectorLayer(self.dbName, self.table_layer, crop__model_name)

        # Retrieve the Spatialite layer and add it to mapp
        uri = QgsDataSourceURI()
        uri.setDatabase(self.dbName)
        schema = ''
        table = crop__model_name
        geom_column = None
        uri.setDataSource(schema, table, geom_column)
        display_name = crop__model_name

        crop_lay = QgsVectorLayer(uri.uri(), display_name, 'spatialite')

        QgsMapLayerRegistry.instance().addMapLayer(crop_lay)

        # pop message depending on the layer validity
        if crop_lay.isValid():
            pop_message(self.tr('Layer correctly created'), 'information')
        else:
            pop_message(self.tr('Something went wrong during the layer creation'), 'critical')
            return

        # create the table to store all the Crop Models and their information
        # name of the crops table
        nameTable = 'crop_models_table'

        # connection to the DB and get the cursor
        con = sqlite3.connect(self.dbName)
        con.enable_load_extension(True)
        cur = con.cursor()

        # check if the table alrerady exists, if not create it else, append the rows
        if nameTable not in self.tableList:
            # create the (empty) table with the fields
            sql_create = 'CREATE TABLE {} ("ID" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "crop_model_name" TEXT, "ts" TEXT, "th" TEXT)'.format(nameTable)

            cur.execute(sql_create)

            # crerate the insert sql statement
            sql_insert = "INSERT INTO {table_name} (ID, crop_model_name, ts, th) VALUES (NULL, '{model_name}', '{ts}', '{th}')".format(table_name=nameTable, model_name=crop_line_name, ts=self.date_ts0, th=self.date_th0)

            cur.execute(sql_insert)
            # Close SpatiaLiteDB
            cur.close()
            # Save the changes
            con.commit()

            # Add the table in the TOC
            uri = QgsDataSourceURI()
            uri.setDatabase(self.dbName)
            schema = ''
            table = nameTable
            geom_column = None
            uri.setDataSource(schema, table, geom_column)
            display_name = nameTable
            tableLayer = QgsVectorLayer(uri.uri(), display_name, 'spatialite')

            QgsMapLayerRegistry.instance().addMapLayer(tableLayer)

        else:
            sql_insert = "INSERT INTO {table_name} (ID, crop_model_name, ts, th) VALUES (NULL, '{model_name}', '{ts}', '{th}')".format(table_name=nameTable, model_name=crop_line_name, ts=self.date_ts0, th=self.date_th0)

            cur.execute(sql_insert)
            # Close SpatiaLiteDB
            cur.close()
            # Save the changes
            con.commit()
