#!/usr/bin/python3
# -*- coding: utf-8 -*-

'''Pychemqt, Chemical Engineering Process simulator
Copyright (C) 2009-2017, Juan José Gómez Romera <jjgomera@gmail.com>

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 3 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, see <http://www.gnu.org/licenses/>.'''


###############################################################################
# Library with meos plugin functionality
#
#   plugin: Implement meos functionality to common use in menu and dialog
#   Menu: QMenu to add to mainwindow mainmenu with all meos addon functionality
#   Dialog: QDialog with all meos functionality
###############################################################################


from configparser import ConfigParser
from functools import partial
from math import log10
import os

from PyQt5 import QtGui, QtWidgets
from numpy import arange, append, concatenate, linspace, logspace
from scipy.optimize import fsolve

from lib import meos, mEoS, unidades, config
from lib.thermo import ThermoAdvanced
from UI.prefMEOS import Dialog as ConfDialog
from UI.widgets import createAction

from .chooseFluid import Ui_ChooseFluid
from .reference import Ui_ReferenceState, Ui_Properties
from .plot import PlotMEoS, Plot2D, Plot3D, calcIsoline, get_points, plot2D3D
from .table import Ui_Saturation, Ui_Isoproperty, createTabla
from .library import getClassFluid, getMethod, calcPoint, N_PROP, KEYS, UNITS


class plugin(object):
    """Common functionality to add to menu and dialog in main window"""

    def _txt(self):
        """Common widget names
        fTxt: Fluid name, dynamic by configuration
        refTxt: Reference state name, dynamic by configuration
        propTxt: Properties option name, fixed
        confTxt: Configure option name, fixed
        """
        if self.config.has_option("MEoS", "fluid"):
            fTxt = mEoS.__all__[self.config.getint("MEoS", "fluid")].name
        else:
            fTxt = QtWidgets.QApplication.translate("pychemqt", "Fluid")
        if self.config.has_option("MEoS", "reference"):
            refTxt = self.config.get("MEoS", "reference")
        else:
            refTxt = QtWidgets.QApplication.translate(
                "pychemqt", "Reference State")
        propTxt = QtWidgets.QApplication.translate("pychemqt", "Properties")
        confTxt = QtWidgets.QApplication.translate("pychemqt", "Configure")

        return fTxt, refTxt, propTxt, confTxt

    def _menuCalculate(self):
        """QMenu for table actions"""
        menu = QtWidgets.QMenu(QtWidgets.QApplication.translate(
            "pychemqt", "Calculate"), parent=self)
        saturationAction = createAction(
            QtWidgets.QApplication.translate("pychemqt", "Saturation"),
            slot=self.showSaturation, parent=self)
        menu.addAction(saturationAction)
        IsopropertyAction = createAction(
            QtWidgets.QApplication.translate("pychemqt", "Isoproperty"),
            slot=self.showIsoproperty, parent=self)
        menu.addAction(IsopropertyAction)
        menu.addSeparator()
        SpecifyAction = createAction(
            QtWidgets.QApplication.translate("pychemqt", "Specified point"),
            slot=self.addTableSpecified, parent=self)
        menu.addAction(SpecifyAction)
        return menu

    def _menuPlot(self):
        """QMenu for plot actions"""
        menu = QtWidgets.QMenu(
            QtWidgets.QApplication.translate("pychemqt", "Plot"), parent=self)
        Plot_T_s_Action = createAction(
            QtWidgets.QApplication.translate("pychemqt", "T-s diagram"),
            slot=partial(self.plot, "s", "T"), parent=self)
        menu.addAction(Plot_T_s_Action)
        Plot_T_rho_Action = createAction(
            QtWidgets.QApplication.translate("pychemqt", "T-rho diagram"),
            slot=partial(self.plot, "rho", "T"), parent=self)
        menu.addAction(Plot_T_rho_Action)
        Plot_P_h_Action = createAction(
            QtWidgets.QApplication.translate("pychemqt", "P-h diagram"),
            slot=partial(self.plot, "h", "P"), parent=self)
        menu.addAction(Plot_P_h_Action)
        Plot_P_v_Action = createAction(
            QtWidgets.QApplication.translate("pychemqt", "P-v diagram"),
            slot=partial(self.plot, "v", "P"), parent=self)
        menu.addAction(Plot_P_v_Action)
        Plot_P_T_Action = createAction(
            QtWidgets.QApplication.translate("pychemqt", "P-T diagram"),
            slot=partial(self.plot, "T", "P"), parent=self)
        menu.addAction(Plot_P_T_Action)
        Plot_h_s_Action = createAction(
            QtWidgets.QApplication.translate("pychemqt", "h-s diagram"),
            slot=partial(self.plot, "s", "h"), parent=self)
        menu.addAction(Plot_h_s_Action)
        Plot_v_u_Action = createAction(
            QtWidgets.QApplication.translate("pychemqt", "v-u diagram"),
            slot=partial(self.plot, "u", "v"), parent=self)
        menu.addAction(Plot_v_u_Action)
        Plot2DAction = createAction(
            QtWidgets.QApplication.translate("pychemqt", "Other Plots"),
            slot=self.plot2D, parent=self)
        menu.addAction(Plot2DAction)
        menu.addSeparator()
        Plot3DAction = createAction(
            QtWidgets.QApplication.translate("pychemqt", "3D Plot"),
            slot=self.plot3D, parent=self)
        menu.addAction(Plot3DAction)
        return menu

    def showChooseFluid(self):
        """Show dialog to choose/view fluid"""
        dlg = Ui_ChooseFluid(self.config)
        if dlg.exec_():
            # Update configuration
            if not self.config.has_section("MEoS"):
                self.config.add_section("MEoS")
            self.config.set("MEoS", "fluid", str(dlg.id()))
            self.config.set("MEoS", "eq", str(dlg.eq.currentIndex()))
            self.config.set("MEoS", "PR", str(dlg.radioPR.isChecked()))
            self.config.set("MEoS", "Generalized",
                            str(dlg.generalized.isChecked()))
            self.config.set("MEoS", "visco", str(dlg.visco.currentIndex()))
            self.config.set("MEoS", "thermal", str(dlg.thermal.currentIndex()))
            self.checkProperties()
            self.parent().dirty[self.parent().idTab] = True
            self.parent().saveControl()

            # Update button text in dialog case
            if self.__class__.__name__ == "Dialog":
                fTxt = mEoS.__all__[dlg.lista.currentRow()].name
                self.fluido.setText(fTxt)

    def showReference(self):
        """Show dialog to choose reference state,
        use for enthalpy and entropy zero state
        Don't implemented yet"""
        dlg = Ui_ReferenceState(self.config)
        if dlg.exec_():
            # Get values
            if not self.config.has_section("MEoS"):
                self.config.add_section("MEoS")
            if dlg.OTO.isChecked():
                refName, refT, refP, refH, refS = "OTO", 298.15, 101325, 0, 0
            elif dlg.NBP.isChecked():
                Tb = mEoS.__all__[self.config.getint("MEoS", "fluid")].Tb
                refName, refT, refP, refH, refS = "NBP", Tb, 101325, 0, 0
            elif dlg.IIR.isChecked():
                refName, refT, refP, refH, refS = "IIR", 273.15, 101325, 200, 1
            elif dlg.ASHRAE.isChecked():
                refName, refT, refP, refH, refS = "ASHRAE", 233.15, 101325,
                refH, refS = 0, 0
            else:
                refName = "Custom"
                refT = dlg.T.value
                refP = dlg.P.value
                refH = dlg.h.value
                refS = dlg.s.value

            # Update configuration
            self.config.set("MEoS", "reference", refName)
            self.config.set("MEoS", "Tref", str(refT))
            self.config.set("MEoS", "Pref", str(refP))
            self.config.set("MEoS", "ho", str(refH))
            self.config.set("MEoS", "so", str(refS))
            self.checkProperties()
            self.parent().dirty[self.parent().idTab] = True
            self.parent().saveControl()

            # Update button text in dialog case
            if self.__class__.__name__ == "Dialog":
                self.reference.setText(refName)

    def checkProperties(self):
        """Add default properties to configuration automatic when choose
        fluid or reference state and properties are not defined"""
        if not self.config.has_option("MEoS", "properties"):
            self.config.set("MEoS", "properties", str(Ui_Properties._default))
            self.config.set("MEoS", "phase", "0")
            self.config.set("MEoS", "propertiesOrder",
                            str(list(range(N_PROP))))

    def showProperties(self):
        """Show dialog to choose/sort properties to show in tables"""
        dlg = Ui_Properties(self.config)
        if dlg.exec_():
            # Update configuration
            if not self.config.has_section("MEoS"):
                self.config.add_section("MEoS")
            self.config.set("MEoS", "properties", str(dlg.properties()))
            self.config.set("MEoS", "phase", str(dlg.checkFase.isChecked()))
            self.config.set("MEoS", "propertiesOrder", str(dlg.order))
            self.parent().dirty[self.parent().idTab] = True
            self.parent().saveControl()

    def configure(self):
        """Direct access to configuration"""
        Config = ConfigParser()
        Config.read(config.conf_dir + "pychemqtrc")
        dlg = ConfDialog(Config)
        if dlg.exec_():
            Config = dlg.value(Config)
            Config.write(open(config.conf_dir+"pychemqtrc", "w"))

    def showSaturation(self):
        """Show dialog to define input for a two-phase saturation table"""
        dlg = Ui_Saturation(self.config)
        if dlg.exec_():
            # Get values
            start = dlg.Inicial.value
            end = dlg.Final.value
            incr = dlg.Incremento.value
            fix = dlg.variableFix.value
            value = arange(start, end, incr)
            if (end-start) % incr == 0:
                value = append(value, end)
            fluid = getClassFluid(self.config)
            method = getMethod()

            fluidos = []
            if dlg.VL.isChecked():
                # Liquid-Gas line
                txt = QtWidgets.QApplication.translate(
                    "pychemqt", "Liquid-Gas Line")
                if dlg.VariarTemperatura.isChecked():
                    # Changing temperature
                    for val in value:
                        vconfig = unidades.Temperature(val).str
                        self.parent().statusbar.showMessage(
                            "%s: %s =%s, %s" % (fluid.name, "T", vconfig, txt))
                        fluidos.append(fluid._new(T=val, x=0.5))
                elif dlg.VariarPresion.isChecked():
                    # Changing pressure
                    for val in value:
                        vconfig = unidades.Temperature(val).str
                        self.parent().statusbar.showMessage(
                            "%s: %s =%s, %s" % (fluid.name, "P", vconfig, txt))
                        fluidos.append(fluid._new(P=val, x=0.5))
                elif dlg.VariarXconT.isChecked():
                    # Changing quality with fixed Temperature
                    fconfig = unidades.Temperature(fix).str
                    for val in value:
                        self.parent().statusbar.showMessage(
                            "%s: T =%s  x = %s, %s" % (
                                fluid.name, fconfig, val, txt))
                        fluidos.append(fluid._new(T=fix, x=val))
                elif dlg.VariarXconP.isChecked():
                    # Changing quality with fixed pressure
                    fconfig = unidades.Temperature(fix).str
                    for val in value:
                        self.parent().statusbar.showMessage(
                            "%s: P =%s  x = %s, %s" % (
                                fluid.name, fconfig, val, txt))
                        fluidos.append(fluid._new(P=fix, x=val))

            else:
                # Melting and sublimation line, only supported for meos
                # internal method
                if dlg.SL.isChecked():
                    func = fluid._Melting_Pressure
                    txt = QtWidgets.QApplication.translate(
                        "pychemqt", "Melting Line")
                elif dlg.SV.isChecked():
                    func = fluid._Sublimation_Pressure
                    txt = QtWidgets.QApplication.translate(
                        "pychemqt", "Sublimation Line")

                if dlg.VariarTemperatura.isChecked():
                    for val in value:
                        p = func(val)
                        fluidos.append(fluid._new(T=val, P=p))
                        self.parent().statusbar.showMessage(
                            "%s: %s=%0.2f, %s" % (fluid.name, "T", val, txt))
                else:
                    for p in value:
                        T = fsolve(lambda T: p-func(T), fluid.Tt)
                        fluidos.append(fluid._new(T=T, P=p))
                        self.parent().statusbar.showMessage(
                            "%s: %s=%0.2f, %s" % (fluid.name, "P", p, txt))

            title = QtWidgets.QApplication.translate(
                "pychemqt", "Table %s: %s changing %s (%s)" % (
                    fluid.name, txt, "T", method))
            self.addTable(fluidos, title)
            self.parent().statusbar.clearMessage()

    def showIsoproperty(self):
        """Show dialog to define input for isoproperty table calculations"""
        dlg = Ui_Isoproperty(self.parent())
        if dlg.exec_():
            self.parent().updateStatus(QtWidgets.QApplication.translate(
                "pychemqt", "Launch MEoS Isoproperty calculation..."))

            # Get data from dialog
            i = dlg.fix.currentIndex()
            j = dlg.vary.currentIndex()
            if j >= i:
                j += 1
            X = dlg.keys[i]
            keys = dlg.keys[:]
            Y = keys[j]
            value1 = dlg.variableFix.value
            start = dlg.Inicial.value
            end = dlg.Final.value
            incr = dlg.Incremento.value
            value2 = arange(start, end, incr)
            if (end-start) % incr == 0:
                value2 = append(value2, end)
            v1conf = dlg.unidades[i](value1).str

            fluid = getClassFluid(self.config)
            method = getMethod()

            kwarg = {}
            # Define option parameter for transport method, only available
            # for internal meos method
            if method == "MEOS":
                for key in ("eq", "visco", "thermal"):
                    kwarg[key] = self.config.getint("MEoS", key)

            fluidos = []
            for v2 in value2:
                kwarg[X] = value1
                kwarg[Y] = v2
                if dlg.unidades[j] == float:
                    v2conf = v2
                else:
                    v2conf = dlg.unidades[j](v2).str
                self.parent().statusbar.showMessage(
                    "%s: %s =%s, %s =%s" % (fluid.name, X, v1conf, Y, v2conf))
                fluidos.append(fluid._new(**kwarg))
            unitX = dlg.unidades[i].text()
            title = QtWidgets.QApplication.translate(
                "pychemqt", "%s: %s =%s %s changing %s (%s)" % (
                    fluid.name, X, v1conf, unitX, meos.propiedades[j],
                    method))
            self.addTable(fluidos, title)

    def addTable(self, fluidos, title):
        """Add table with properties to mainwindow
        fluidos: List with fluid instances
        title: Text title for window table"""
        tabla = createTabla(self.config, title, fluidos, self.parent())
        self.parent().centralwidget.currentWidget().addSubWindow(tabla)
        wdg = self.parent().centralwidget.currentWidget().subWindowList()[-1]
        wdg.setWindowIcon(QtGui.QIcon(QtGui.QPixmap(tabla.icon)))
        tabla.show()

    def addTableSpecified(self):
        """Add blank table to mainwindow to calculata point data"""
        fluid = getClassFluid(self.config)
        name = fluid.name
        method = getMethod()
        title = "%s: %s (%s)" % (name, QtWidgets.QApplication.translate(
            "pychemqt", "Specified state points"), method)
        tabla = createTabla(self.config, title, None, self.parent())
        tabla.Point = fluid
        self.parent().centralwidget.currentWidget().addSubWindow(tabla)
        wdg = self.parent().centralwidget.currentWidget().subWindowList()[-1]
        wdg.setWindowIcon(QtGui.QIcon(QtGui.QPixmap(tabla.icon)))
        tabla.show()

    def plot2D(self):
        """Add a generic 2D plot to project"""
        dlg = Plot2D(self.parent())
        if dlg.exec_():
            i = dlg.ejeX.currentIndex()
            j = dlg.ejeY.currentIndex()
            if j >= i:
                j += 1
            prop = ThermoAdvanced.propertiesKey()
            x = prop[i]
            y = prop[j]

            if dlg.Xscale.isChecked():
                xscale = "log"
            else:
                xscale = "linear"
            if dlg.Yscale.isChecked():
                yscale = "log"
            else:
                yscale = "linear"
            self.plot(x, y, xscale, yscale)

    def plot3D(self):
        """Add a generic 3D plot to project"""
        dlg = Plot3D(self.parent())
        if dlg.exec_():
            i = dlg.ejeX.currentIndex()
            j = dlg.ejeY.currentIndex()
            k = dlg.ejeZ.currentIndex()
            if k >= i:
                k += 1
            if k >= j:
                k += 1
            if j >= i:
                j += 1
            prop = ThermoAdvanced.propertiesKey()
            x = prop[i]
            y = prop[j]
            z = prop[k]
            self.plot(x, y, z=z)

    def plot(self, x, y, xscale=None, yscale=None, z=""):
        """Create a plot
        x: property for axes x
        y: property for axes y
        xscale: scale for axis x
        yscale: scale for axis y
        z: property for axis z, optional to 3D plot"""
        fluid = getClassFluid(self.config)
        method = getMethod()
        filename = "%s-%s.pkl" % (method, fluid.name)

        if z:
            title = QtWidgets.QApplication.translate(
                "pychemqt", "Plot %s: %s=f(%s,%s)" % (fluid.name, z, y, x))
            dim = 3
        else:
            title = QtWidgets.QApplication.translate(
                "pychemqt", "Plot %s: %s=f(%s)" % (fluid.name, y, x))
            dim = 2
        grafico = PlotMEoS(dim=dim, parent=self.parent(), filename=filename)
        grafico.setWindowTitle(title)
        grafico.x = x
        grafico.y = y
        grafico.z = z

        unitx = UNITS[KEYS.index(x)].magnitudes()[0][0]
        unity = UNITS[KEYS.index(y)].magnitudes()[0][0]
        i = self.config.getint("Units", unitx)
        j = self.config.getint("Units", unity)
        xtxt = "%s, %s" % (x, UNITS[KEYS.index(x)].__text__[i])
        ytxt = "%s, %s" % (y, UNITS[KEYS.index(y)].__text__[j])
        grafico.plot.ax.set_xlabel(xtxt)
        grafico.plot.ax.set_ylabel(ytxt)
        if z:
            grafico.z = z
            unitz = UNITS[KEYS.index(z)].magnitudes()[0][0]
            k = self.config.getint("Units", unitz)
            ztxt = "%s, %s" % (z, UNITS[KEYS.index(z)].__text__[k])
            grafico.plot.ax.set_zlabel(ztxt)

        self.parent().statusbar.showMessage(QtWidgets.QApplication.translate(
            "pychemqt", "Loading cached data..."))
        QtWidgets.QApplication.processEvents()
        data = grafico._getData()
        if not data:
            self.parent().progressBar.setValue(0)
            self.parent().progressBar.setVisible(True)
            self.parent().statusbar.showMessage(
                QtWidgets.QApplication.translate(
                    "pychemqt", "Calculating data, be patient..."))
            QtWidgets.QApplication.processEvents()
            data = self.calculatePlot(fluid)
            conf = {}
            conf["method"] = method
            conf["fluid"] = self.config.getint("MEoS", "fluid")
            conf["eq"] = self.config.getint("MEoS", "eq")
            conf["visco"] = self.config.getint("MEoS", "visco")
            conf["thermal"] = self.config.getint("MEoS", "thermal")
            data["config"] = conf
            grafico._saveData(data)
            self.parent().progressBar.setVisible(False)
        self.parent().statusbar.showMessage(
            QtWidgets.QApplication.translate("pychemqt", "Plotting..."))
        QtWidgets.QApplication.processEvents()
        grafico.config = data["config"]

        if z:
            plot2D3D(grafico, data, config.Preferences, x, y, z)
        else:
            plot2D3D(grafico, data, config.Preferences, x, y)

            if not xscale:
                if x in ["P", "rho", "v"]:
                    xscale = "log"
                else:
                    xscale = "linear"
            grafico.plot.ax.set_xscale(xscale)
            if not yscale:
                if y in ["P", "rho", "v"]:
                    yscale = "log"
                else:
                    yscale = "linear"
            grafico.plot.ax.set_yscale(yscale)

        grid = config.Preferences.getboolean("MEOS", "grid")
        grafico.plot.ax._gridOn = grid
        grafico.plot.ax.grid(grid)

        self.parent().centralwidget.currentWidget().addSubWindow(grafico)
        grafico.show()
        self.parent().statusbar.clearMessage()

    def calculatePlot(self, fluid):
        """Calculate data for plot
            fluid: class of meos fluid to calculate"""
        data = {}
        points = get_points(config.Preferences)
        method = getMethod()

        # Melting and sublimation line only supported in internal meos method
        if method == "MEOS":
            # Calculate melting line
            if fluid._melting:
                self.parent().statusbar.showMessage(
                    QtWidgets.QApplication.translate(
                        "pychemqt", "Calculating melting line..."))
                T = linspace(fluid._melting["Tmin"], fluid._melting["Tmax"],
                             points)
                fluidos = []
                for Ti in T:
                    P = fluid._Melting_Pressure(Ti)
                    fluido = calcPoint(fluid, self.config, T=Ti, P=P)
                    if fluido:
                        fluidos.append(fluido)
                    self.parent().progressBar.setValue(5*len(fluidos)/len(T))
                    QtWidgets.QApplication.processEvents()
                if fluidos:
                    data["melting"] = {}
                    for x in ThermoAdvanced.propertiesKey():
                        dat_propiedad = []
                        for fluido in fluidos:
                            num = fluido.__getattribute__(x)
                            if num is not None:
                                if x in ["fi", "f"]:
                                    num = num[0]
                                dat_propiedad.append(num._data)
                            else:
                                dat_propiedad.append(None)
                        data["melting"][x] = dat_propiedad

            # Calculate sublimation line
            if fluid._sublimation:
                self.parent().statusbar.showMessage(
                    QtWidgets.QApplication.translate(
                        "pychemqt", "Calculating sublimation line..."))
                T = linspace(fluid._sublimation["Tmin"],
                             fluid._sublimation["Tmax"], points)
                fluidos = []
                for Ti in T:
                    P = fluid._Sublimation_Pressure(Ti)
                    fluido = calcPoint(fluid, self.config, T=Ti, P=P)
                    if fluido:
                        fluidos.append(fluido)
                    self.parent().progressBar.setValue(5+5*len(fluidos)/len(T))
                    QtWidgets.QApplication.processEvents()
                if fluidos:
                    data["sublimation"] = {}
                    for x in ThermoAdvanced.propertiesKey():
                        dat_propiedad = []
                        for fluido in fluidos:
                            num = fluido.__getattribute__(x)
                            if num is not None:
                                if x in ["fi", "f"]:
                                    num = num[0]
                                dat_propiedad.append(num._data)
                            else:
                                dat_propiedad.append(None)
                        data["sublimation"][x] = dat_propiedad

        # Define the saturation temperature
        T = list(concatenate([linspace(fluid.Tt, 0.9*fluid.Tc, points),
                              linspace(0.9*fluid.Tc, 0.99*fluid.Tc, points),
                              linspace(0.99*fluid.Tc, fluid.Tc, points)]))
        for i in range(2, 0, -1):
            del T[points*i]

        # Calculate saturation
        self.parent().statusbar.showMessage(QtWidgets.QApplication.translate(
            "pychemqt", "Calculating Liquid-Vapour saturation line..."))
        for fase in [0, 1]:
            fluidos = []
            for Ti in T:
                fluidos.append(fluid._new(T=Ti, x=fase))
                self.parent().progressBar.setValue(
                    10+5*fase+5*len(fluidos)/len(T))
                QtWidgets.QApplication.processEvents()

            data["saturation_%i" % fase] = {}
            for key in ThermoAdvanced.propertiesKey():
                dat_propiedad = []
                for fluido in fluidos:
                    if fluido.status:
                        p = fluido.__getattribute__(key)
                        if key in ["fi", "f"]:
                            p = p[0]
                        dat_propiedad.append(p)
                data["saturation_%i" % fase][key] = dat_propiedad

        # Calculate isoquality lines
        data["x"] = {}
        self.parent().statusbar.showMessage(QtWidgets.QApplication.translate(
            "pychemqt", "Calculating isoquality lines..."))
        values = self.LineList("Isoquality", config.Preferences)
        for i, value in enumerate(values):
            fluidos = calcIsoline(fluid, self.config,
                                  "T", "x", T, value, 20, i, 20,
                                  len(values), self.parent().progressBar)

            data["x"][value] = {}
            for x in ThermoAdvanced.propertiesKey():
                dat_propiedad = []
                for fluido in fluidos:
                    if fluido is not None and fluido.status:
                        p = fluido.__getattribute__(key)
                        if key in ["fi", "f"]:
                            p = p[0]
                        dat_propiedad.append(p)
                    else:
                        dat_propiedad.append(None)
                data["x"][value][x] = dat_propiedad

        # Get limit equation
        if method == "MEOS":
            eq = fluid.eq[self.parent().currentConfig.getint("MEoS", "eq")]
            Tmin = eq["Tmin"]
            Tmax = eq["Tmax"]

            Tt = eq.get("Tt", fluid.Tt)
            if Tmin > Tt:
                Lt = fluid(T=Tmin, x=0)
            else:
                Lt = fluid(T=Tt, x=0)
            Pmin = Lt.P

            Pmax = eq["Pmax"]*1000
        elif method == "COOLPROP":
            Tmin = fluid.eq["Tmin"]
            Tmax = fluid.eq["Tmax"]
            Pmin = fluid.eq["Pmin"]
            Pmax = fluid.eq["Pmax"]
        elif method == "REFPROP":
            pass

        T = list(concatenate(
            [linspace(Tmin, 0.9*fluid.Tc, points),
             linspace(0.9*fluid.Tc, 0.99*fluid.Tc, points),
             linspace(0.99*fluid.Tc, fluid.Tc, points),
             linspace(fluid.Tc, 1.01*fluid.Tc, points),
             linspace(1.01*fluid.Tc, 1.1*fluid.Tc, points),
             linspace(1.1*fluid.Tc, Tmax, points)]))
        P = list(concatenate(
            [logspace(log10(Pmin), log10(0.9*fluid.Pc), points),
             linspace(0.9*fluid.Pc, 0.99*fluid.Pc, points),
             linspace(0.99*fluid.Pc, fluid.Pc, points),
             linspace(fluid.Pc, 1.01*fluid.Pc, points),
             linspace(1.01*fluid.Pc, 1.1*fluid.Pc, points),
             logspace(log10(1.1*fluid.Pc), log10(Pmax), points)]))
        for i in range(5, 0, -1):
            del T[points*i]
            del P[points*i]

        # Calculate isotherm lines
        data["T"] = {}
        self.parent().statusbar.showMessage(QtWidgets.QApplication.translate(
            "pychemqt", "Calculating isotherm lines..."))
        values = self.LineList("Isotherm", config.Preferences, fluid)
        for i, value in enumerate(values):
            fluidos = calcIsoline(fluid, self.config,
                                  "P", "T", P, value, 40, i, 10,
                                  len(values), self.parent().progressBar)
            data["T"][value] = {}
            for key in ThermoAdvanced.propertiesKey():
                dat_propiedad = []
                for fluido in fluidos:
                    if fluido is not None and fluido.status:
                        p = fluido.__getattribute__(key)
                        if key in ["fi", "f"]:
                            p = p[0]
                        dat_propiedad.append(p)
                    else:
                        dat_propiedad.append(None)
                data["T"][value][key] = dat_propiedad

        # Calculate isobar lines
        data["P"] = {}
        self.parent().statusbar.showMessage(QtWidgets.QApplication.translate(
            "pychemqt", "Calculating isobar lines..."))
        values = self.LineList("Isobar", config.Preferences, fluid)
        for i, value in enumerate(values):
            fluidos = calcIsoline(fluid, self.config,
                                  "T", "P", T, value, 50, i, 10,
                                  len(values), self.parent().progressBar)
            data["P"][value] = {}
            for key in ThermoAdvanced.propertiesKey():
                dat_propiedad = []
                for fluido in fluidos:
                    if fluido is not None and fluido.status:
                        p = fluido.__getattribute__(key)
                        if key in ["fi", "f"]:
                            p = p[0]
                        dat_propiedad.append(p)
                    else:
                        dat_propiedad.append(None)
                data["P"][value][key] = dat_propiedad

        # Calculate isochor lines
        data["v"] = {}
        self.parent().statusbar.showMessage(QtWidgets.QApplication.translate(
            "pychemqt", "Calculating isochor lines..."))
        values = self.LineList("Isochor", config.Preferences, fluid)
        for i, value in enumerate(values):
            fluidos = calcIsoline(fluid, self.config,
                                  "T", "v", T, value, 60, i, 10,
                                  len(values), self.parent().progressBar)
            data["v"][value] = {}
            for key in ThermoAdvanced.propertiesKey():
                dat_propiedad = []
                for fluido in fluidos:
                    if fluido is not None and fluido.status:
                        p = fluido.__getattribute__(key)
                        if key in ["fi", "f"]:
                            p = p[0]
                        dat_propiedad.append(p)
                    else:
                        dat_propiedad.append(None)
                data["v"][value][key] = dat_propiedad

        # Calculate isoenthalpic lines
        data["h"] = {}
        self.parent().statusbar.showMessage(QtWidgets.QApplication.translate(
            "pychemqt", "Calculating isoenthalpic lines..."))
        vals = self.LineList("Isoenthalpic", config.Preferences, fluid)
        for i, value in enumerate(vals):
            fluidos = calcIsoline(fluid, self.config,
                                  "P", "h", P, value, 70, i, 10,
                                  len(values), self.parent().progressBar)
            data["h"][value] = {}
            for key in ThermoAdvanced.propertiesKey():
                dat_propiedad = []
                for fluido in fluidos:
                    if fluido is not None and fluido.status:
                        p = fluido.__getattribute__(key)
                        if key in ["fi", "f"]:
                            p = p[0]
                        dat_propiedad.append(p)
                    else:
                        dat_propiedad.append(None)
                data["h"][value][key] = dat_propiedad

        # Calculate isoentropic lines
        data["s"] = {}
        self.parent().statusbar.showMessage(QtWidgets.QApplication.translate(
            "pychemqt", "Calculating isoentropic lines..."))
        values = self.LineList("Isoentropic", config.Preferences, fluid)
        for i, value in enumerate(values):
            fluidos = calcIsoline(fluid, self.config,
                                  "P", "s", P, value, 80, i, 20,
                                  len(values), self.parent().progressBar)
            data["s"][value] = {}
            for key in ThermoAdvanced.propertiesKey():
                dat_propiedad = []
                for fluido in fluidos:
                    if fluido is not None and fluido.status:
                        p = fluido.__getattribute__(key)
                        if key in ["fi", "f"]:
                            p = p[0]
                        dat_propiedad.append(p)
                    else:
                        dat_propiedad.append(None)
                data["s"][value][key] = dat_propiedad

        return data

    @staticmethod
    def LineList(name, Preferences, fluid=None):
        """Return a list with the values of isoline name to plot"""
        if Preferences.getboolean("MEOS", name+"Custom"):
            t = []
            for i in Preferences.get("MEOS", name+'List').split(','):
                if i:
                    t.append(float(i))
        else:
            start = Preferences.getfloat("MEOS", name+"Start")
            end = Preferences.getfloat("MEOS", name+"End")
            step = Preferences.getfloat("MEOS", name+"Step")
            t = list(arange(start, end+step, step))

        if fluid is not None and Preferences.getboolean("MEOS", name+"Critic"):
            if name == "Isotherm":
                t.append(fluid.Tc)
            elif name == "Isobar":
                t.append(fluid.Pc)
            elif name == "Isochor":
                t.append(1./fluid.rhoc)
            else:
                prop = {"Isoenthalpic": "h",
                        "Isoentropic": "s"}
                fc = fluid._new(T=fluid.Tc, rho=fluid.rhoc)
                t.append(fc.__getattribute__(prop[name]))
        return t


# Plugin to import in mainwindow, it implement all meos functionality as QMenu
class Menu(QtWidgets.QMenu, plugin):
    """QMenu to import in mainwindow with all meos addon functionality"""
    def __init__(self, parent=None):
        title = QtWidgets.QApplication.translate("pychemqt", "MEoS properties")
        super(Menu, self).__init__(title, parent)
        self.setIcon(QtGui.QIcon(
            os.path.join(config.IMAGE_PATH, "button", "tables.png")))
        self.aboutToShow.connect(self.aboutToShow_menu)

    def aboutToShow_menu(self):
        """Populate menu, check if fluid and reference state are defined to
        enable/disable calculation/plot option"""
        self.clear()
        self.config = self.parent().currentConfig

        fTxt, refTxt, propTxt, confTxt = self._txt()
        flAction = createAction(fTxt, slot=self.showChooseFluid, parent=self)
        refAction = createAction(refTxt, slot=self.showReference, parent=self)
        pAction = createAction(propTxt, slot=self.showProperties, parent=self)
        confAction = createAction(confTxt, slot=self.configure, parent=self)
        menuCalculate = self._menuCalculate()
        menuPlot = self._menuPlot()
        self.addAction(flAction)
        self.addAction(refAction)
        self.addAction(pAction)
        self.addAction(confAction)
        self.addSeparator()
        self.addAction(menuCalculate.menuAction())
        self.addAction(menuPlot.menuAction())
        self.addSeparator()

        # Disable calculation action if fluid and reference are not defined
        if not (self.config.has_option("MEoS", "fluid") and
                self.config.has_option("MEoS", "reference")):
            menuCalculate.setEnabled(False)
            menuPlot.setEnabled(False)


# Dialog with all meos functionality, to associate to a button in tools toolbar
class Dialog(QtWidgets.QDialog, plugin):
    """Dialog to choose fluid for meos plugins calculations"""
    def __init__(self, config=None, parent=None):
        super(Dialog, self).__init__(parent)
        if config is None:
            config = parent.currentConfig
        self.config = config
        self.setWindowTitle(
            QtWidgets.QApplication.translate("pychemqt", "Choose fluid"))
        layout = QtWidgets.QGridLayout(self)

        fTxt, refTxt, propTxt, confTxt = self._txt()
        fluid = QtWidgets.QPushButton(fTxt)
        fluid.clicked.connect(self.showChooseFluid)
        layout.addWidget(fluid, 1, 1)
        ref = QtWidgets.QPushButton(refTxt)
        ref.clicked.connect(self.showReference)
        layout.addWidget(ref, 2, 1)
        prop = QtWidgets.QPushButton(propTxt)
        prop.clicked.connect(self.showProperties)
        layout.addWidget(prop, 3, 1)
        conf = QtWidgets.QPushButton(confTxt)
        conf.clicked.connect(self.configure)
        layout.addWidget(conf, 4, 1)

        layout.addItem(QtWidgets.QSpacerItem(
            10, 10, QtWidgets.QSizePolicy.Fixed,
            QtWidgets.QSizePolicy.Fixed), 5, 1)
        menuCalculate = self._menuCalculate()
        calculate = QtWidgets.QPushButton(menuCalculate.title())
        calculate.setMenu(menuCalculate)
        layout.addWidget(calculate, 6, 1)
        menuPlot = self._menuPlot()
        plot = QtWidgets.QPushButton(menuPlot.title())
        plot.setMenu(menuPlot)
        layout.addWidget(plot, 6, 2)

        # Disable calculation action if fluid and reference are not defined
        if not (self.config.has_option("MEoS", "fluid") and
                self.config.has_option("MEoS", "reference")):
            calculate.setEnabled(False)
            plot.setEnabled(False)

        layout.addItem(QtWidgets.QSpacerItem(
            0, 0, QtWidgets.QSizePolicy.Expanding,
            QtWidgets.QSizePolicy.Expanding), 7, 1, 1, 3)
        btBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Close)
        btBox.clicked.connect(self.reject)
        layout.addWidget(btBox, 8, 1, 1, 3)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)

    conf = config.getMainWindowConfig()

    # SteamTables = AddPoint(conf)
    # SteamTables=AddLine(None)
    # SteamTables = Dialog(conf)
    SteamTables = Plot3D()

    SteamTables.show()
    sys.exit(app.exec_())