#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 PyQt4 import QtGui
import os
import itertools
from string import ascii_uppercase
from datetime import datetime
from utils.TableUtils import  addCellInRow, addHeader
from external.odf.opendocument import OpenDocumentSpreadsheet
from external.odf.style import Style, TextProperties, TableCellProperties
from external.odf.table import Table, TableRow, TableCell
from external.odf.number import DateStyle, Year, Text, Month, Day, Hours, Minutes, Seconds

from AKFeatureResults import AKFeatureResults

class AKFeatureResultsIonicBalance(AKFeatureResults):
    '''
    This feature provides the functionality for the second Ionic Balance form. 
    '''
    def __init__(self, settings, iface, windowTitle="", parent=None):
        if windowTitle is "":
            windowTitle = u"Ionic Balance Results"
        super(AKFeatureResultsIonicBalance, self).__init__(settings, iface, windowTitle=windowTitle, parent=parent)

    def customizeForm(self):        
        super(AKFeatureResultsIonicBalance, self).customizeForm()        
        self.m_form.plotButton.setText("Save Report (Only Open Office)")
        
    def initialize(self):
        self.showData(hideMeasurements=True)
        super(AKFeatureResultsIonicBalance, self).initialize()
      
    def loadStyles(self, textdoc):        
        backgroundcolor = "#F5ECCE"
        styleName1 = "MyStyle1"                
        style = Style(name=styleName1, family="table-cell")
        style.addElement(TextProperties(color="#000000",fontname="Arial", fontsize="10pt"))
        style.addElement(TableCellProperties(backgroundcolor=backgroundcolor))
        textdoc.automaticstyles.addElement(style)
        
        backgroundcolor = "#E6E6E6"
        styleName2 = "MyStyle2"
        style = Style(name=styleName2, family="table-cell")
        style.addElement(TextProperties(color="#000000",fontname="Arial", fontsize="10pt"))
        style.addElement(TableCellProperties(backgroundcolor=backgroundcolor))
        textdoc.automaticstyles.addElement(style)
        
        date_style = DateStyle(name="date-style1") #, language="lv", country="LV")
        date_style.addElement(Year(style="long"))
        date_style.addElement(Text(text=u"-"))
        date_style.addElement(Month(style="long"))
        date_style.addElement(Text(text=u"-"))
        date_style.addElement(Day(style="long"))
        date_style.addElement(Text(text=u" "))
        date_style.addElement(Hours(style="long"))
        date_style.addElement(Text(text=u":"))
        date_style.addElement(Minutes(style="long"))
        date_style.addElement(Text(text=u":"))
        date_style.addElement(Seconds(style="long", decimalplaces="3"))
        textdoc.automaticstyles.addElement(date_style)
        #link to generated style from content.xml
        ds = Style(name="ds1", datastylename="date-style1",parentstylename="Default", family="table-cell")
        
        pass
    
    def onActionClicked(self):
        files_types = "LibreOffice (*.ods)"
        filename = QtGui.QFileDialog.getSaveFileName(self.m_form, "Save ionic balance report", os.getenv("HOME"), files_types)
        if filename == "":
            return
        
        model = self.sampleMeasurementsModel
            
        textdoc = OpenDocumentSpreadsheet()       
        self.loadStyles(textdoc)
        
        self.writeIonicBalanceReport(model, textdoc)

        textdoc.save(filename)
        
    def loadData(self, model, dataOrder, data):
        
        # initialize
        for group in dataOrder:
            params = data[group]["param"]
            for curParam in params:
                data[group]["values"][curParam] = []
 
        # get All values
        numOfSamples = model.rowCount()
        for row in range(numOfSamples):
            isValid = model.data(self.sampleMeasurementsModel.index(row, model.COLUMNS["valid"]))
            if(isValid):
            
                for group in dataOrder:
                    params = data[group]["param"]
                    
                    if group == "basicFields":
                        for curParam in params:
                            val = model.data(model.index(row, model.COLUMNS[curParam]))                            
                            if (curParam == "Date"):
                                val =  datetime.strptime(val, "%Y-%m-%d %H:%M:%S.%f")                               
                                
                            data[group]["values"][curParam].append(val)    
                                
                            
                    elif group in ["generalParams", "cations_mgl", "anions_mgl"]:
                        
                        for curParam in params:
                            value = None
                            for column in self.columnsOfInterest[curParam]["relatedParamIds"]:
                                if(model.data(model.index(row, model.COLUMNS[column])) != None):
                                    value = model.data(model.index(row, model.COLUMNS[column]))
                                    break
                            
                            data[group]["values"][curParam].append(value)
                    
                    elif group in ["cations_meq", "anions_meq"]:
                        for curParam in params:
                            value = None
                            curParamInfo = self.paramInfo[curParam]
    
                            columnId = curParamInfo["id"]
                            value = model.data(model.index(row, model.COLUMNS[columnId]))  
                            data[group]["values"][curParam].append(value)
        
    def writeIonicBalanceReport(self, model, textdoc):

        # Start the table, and describe the columns
        table = Table(name="Ionic balance")

        #Ca, Cl, Mg, Na,SO4,HCO3,K,NH4,NO3,TAC, CE,pH,DUR,TSD, Temperature        
        # information for loops
        paramList = {"N209MQL":"Ca","N247MQL":"Cl" ,"N436MQL":"Mg" ,"N580MQL":"Na","N582MQL":"SO4","N168MQL":"HCO3",
                     "N553MQL":"K","N592MQL":"TAC","N480MQL":"NO3","N216USC":"CE","N540UNK":"pH","N326UNK":"DUR",
                     "N647UNK":"TSD","N124MQL":"NH4", "N595GCG":"Temperature"}
        
        cations = ["N209MQL", "N436MQL", "N580MQL", "N553MQL"]
        anions = ["N247MQL", "N582MQL", "N168MQL", "N480MQL"]
        generalParams = ["N592MQL", "N124MQL", "N216USC", "N540UNK", "N326UNK", "N647UNK", "N595GCG"]
        generalParamsUnits = {"TAC":"(mgl)", "NH4":"(meq/l)", "CE":"(uscm3)", "pH":"", "DUR": "(mgl)", "TSD":"", "Temperature":"(degC)"}        
        basicFields =["Sample", "Point", "Coordinate X", "Coordinate Y", "Campaign", "Date"]
        
        groupNeedsTotal = ["cations_mgl", "anions_mgl", "cations_meq", "anions_meq"]

        dataOrder = ["basicFields", "generalParams", "cations_mgl", "anions_mgl", "cations_meq", "anions_meq", "cations_mgl_percentage", "anions_mgl_percentage", "cations_meq_percentage", "anions_meq_percentage", "ionic_balance"]
        data = {}
        data["basicFields"]= {"title":'QGis Fields', "values":{},"param":basicFields, "nameFromParamList":False, "specificUnits": False, "units":""}
        data["generalParams"]= {"title":'General parameters',"values":{}, "param":generalParams, "nameFromParamList":True, "specificUnits": True, "units":generalParamsUnits}
        data["cations_mgl"]= {"title":'Cations in mg/l',"values":{}, "param":cations, "nameFromParamList":True,"specificUnits": False, "units":"(mgl)"}
        data["anions_mgl"]= {"title":'Anions in mg/l',"values":{}, "param":anions,"nameFromParamList":True,"specificUnits": False, "units":"(mgl)"}
        data["cations_meq"]= {"title":'Cations in meq/l',"values":{}, "param":cations, "nameFromParamList":True,"specificUnits": False, "units":"(meql)"}
        data["anions_meq"]= {"title":'Anions in meq/l',"values":{}, "param":anions, "nameFromParamList":True,"specificUnits": False, "units":"(meql)"}
        data["cations_mgl_percentage"]= {"title":'Cations Weight Percentage',"values":{}, "param":cations, "nameFromParamList":True,"specificUnits": False, "units":"(mgl %)"}
        data["anions_mgl_percentage"]= {"title":'Anions Weight Percentage',"values":{}, "param":anions,"nameFromParamList":True,"specificUnits": False, "units":"(mgl %)"}
        data["cations_meq_percentage"]= {"title":'Cations meq Percentage',"values":{}, "param":cations, "nameFromParamList":True,"specificUnits": False, "units":"(meql %)"}
        data["anions_meq_percentage"]= {"title":'Anions  meq Percentage',"values":{}, "param":anions, "nameFromParamList":True,"specificUnits": False, "units":"(meql %)"}
        data["ionic_balance"]= {"title":'Ionic Balance Error',"values":{}, "param":["Error(%)"], "nameFromParamList":False,"specificUnits": False, "units":""}      

        # apply styles
        styleName1 = "MyStyle1"
        styleName2 = "MyStyle2" 
        styleHeader = itertools.cycle([styleName1, styleName2])
        
        # load data from model
        self.loadData(model, dataOrder, data)
        
        numOfSamples = len(data["basicFields"]["values"]["Sample"])
        
        # main header row                
        header1_row = TableRow()                
        table.addElement(header1_row)
        
        for group in dataOrder:
            
            val = data[group]["title"]
            params = data[group]["param"]
            numCols =  len(params)
            if group in ["cations_mgl", "anions_mgl", "cations_meq", "anions_meq"]:
                numCols += 1
            addHeader(textdoc, header1_row, val, numCols, styleHeader.next())

        # subheader row
        header2_row = TableRow()
        table.addElement(header2_row)
        
        for group in dataOrder:
            
            val = data[group]["title"]
            params = data[group]["param"]

            if not data[group]["nameFromParamList"]:
                for curParam in params:
                    addCellInRow(header2_row, curParam)
            else:
                units = ""
                for curParam in params:
                    units = data[group]["units"]
                    paramName = paramList[curParam]
                    if data[group]["specificUnits"]:
                        units = data[group]["units"][paramName]
                    
                    header = paramName +units                   
                    addCellInRow(header2_row, header)
                if group in ["cations_mgl", "anions_mgl", "cations_meq", "anions_meq"]:
                    addCellInRow(header2_row, "Total"+units)
        
        # data
        letterList = list(ascii_uppercase) + [letter1+letter2 for letter1 in ascii_uppercase for letter2 in ascii_uppercase]        
        totalColumnsDistance = 2*(len(anions)+len(cations)+2)
        
        for row in range(numOfSamples):
            curExcelColumn = 0
            curExcelRow = row+3
            tr = TableRow()
            table.addElement(tr)
            for group in dataOrder:
                if group in ["basicFields", "generalParams"]:                
                    params = data[group]["param"]
    
                    for curParam in params:
                        val =  data[group]["values"][curParam][row]
                        addCellInRow(tr, val)
                        curExcelColumn +=1
                elif group in ["cations_mgl", "anions_mgl", "cations_meq", "anions_meq"]:
                    params = data[group]["param"]
                    for curParam in params:
                        val =  data[group]["values"][curParam][row]
                        addCellInRow(tr, val)
                        curExcelColumn +=1
                    formula = "=SUM("+letterList[curExcelColumn-len(params)]+str(curExcelRow)+":"+letterList[curExcelColumn-1]+str(curExcelRow)+")"
                    
                    tc = TableCell(formula=formula, valuetype='float')
                    tr.addElement(tc)
                    curExcelColumn +=1
                elif group in ["cations_mgl_percentage", "anions_mgl_percentage", "cations_meq_percentage", "anions_meq_percentage"]:
                    params = data[group]["param"]
                    iniColumn = curExcelColumn
                    for curParam in params:
                        formula = "="+letterList[curExcelColumn-totalColumnsDistance]+str(curExcelRow)+"/"+letterList[iniColumn-totalColumnsDistance+len(params)]+str(curExcelRow)
                        tc = TableCell(formula=formula, valuetype='percentage')
                        tr.addElement(tc)
                        curExcelColumn +=1
                    curExcelColumn +=1                    
                elif group in ["ionic_balance"]:
                    formula = "=200*(AB3-AG3)/((AB3+AG3)) ".replace("3", str(curExcelRow))
                    tc = TableCell(formula=formula, valuetype='float')
                    tr.addElement(tc)
                    curExcelColumn +=1
        textdoc.spreadsheet.addElement(table)
        
        
    def addValidColumn(self, paramInfo, parameterOrder):
        model = self.sampleMeasurementsModel
        model.addSimpleColumn("valid")
        numOfSamples = model.rowCount()
        
        #{"N209MQL":"Ca","N247MQL":"Cl" ,"N436MQL":"Mg" ,"N580MQL":"Na","N582MQL":"SO4","N168MQL":"HCO3",
        # "N553MQL":"K",", "N480MQL":"NO3"}
        
        importantParams = ["N209MQL","N247MQL","N436MQL","N580MQL","N582MQL","N168MQL",
                                      "N553MQL","N480MQL"]
        
        for row in range(numOfSamples):
            valid = True
            for paramName in importantParams:
                paramId = paramInfo[paramName]["id"]
                columnIndex = model.COLUMNS[paramId]
                newValue = model.data(model.index(row, columnIndex))
                if(newValue == None):
                    valid = False
            self.sampleMeasurementsModel.setData(self.sampleMeasurementsModel.index(row, model.COLUMNS["valid"]), valid)        

    def postProcessModelData(self, paramInfo, parameterOrder):
        super(AKFeatureResultsIonicBalance, self).postProcessModelData(paramInfo, parameterOrder)

        self.addValidColumn(paramInfo, parameterOrder)
        