# Copyright (c) 2011-2014, B.I.Stepanov Institute of Physics, National Academy
# of Sciences of Belarus.
#
# 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.

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from common.utils import txt

from common.ParamsCollection import *
from common.ParamsDialog import *

__all__ = ['LiricPerturbanceParams', 'LiricPerturbanceParamsDialog']

# *****************************************************************************
class LiricPerturbanceParams(ParamsCollection):
    """Parameters for the procedure of estimating LIRIC algorithm's stability
    to perturbances in its input data."""

    # ---- Class attributes ---------------------------------------------------
    parameterList = [
        # ---- Global switch ----
        ParameterInfo('Global_switch', '&Enable perturbance analysis',
            'perturbanceEnabled', bool, False),

        # ---- Number of evaluations ----
        ParameterInfo('Number_of_evaluations', 'm =',
            'evaluations', int, 5, minValue = 1),

        # ---- White noise ----
        ParameterHeader('White_noise', 'Amplitude:'),
        ParameterInfo('White_noise', 'e<sub>355</sub> =',
            'whiteNoise355', float, 0.2, minValue = 0.0),
        ParameterInfo('White_noise', 'e<sub>532</sub> =',
            'whiteNoise532', float, 0.2, minValue = 0.0),
        ParameterInfo('White_noise', 'e<sub>1064</sub> =',
            'whiteNoise1064', float, 0.2, minValue = 0.0),
        ParameterInfo('White_noise', u'e<sub>532,\u22a5</sub> =',
            'whiteNoise532C', float, 0.2, minValue = 0.0),
        ParameterHeader('White_noise', 'Common amplitude:'),
        ParameterInfo('White_noise', 'b =',
            'whiteNoiseCommon', float, 1.0, minValue = 0.0),

        # ---- Linear perturbance -----
        ParameterHeader('Linear_perturbance', 'Linear factor:'),
        ParameterInfo('Linear_perturbance', 'k<sub>355</sub> =',
            'linear355', float, 0.2, minValue = 0.0),
        ParameterInfo('Linear_perturbance', 'k<sub>532</sub> =',
            'linear532', float, 0.2, minValue = 0.0),
        ParameterInfo('Linear_perturbance', 'k<sub>1064</sub> =',
            'linear1064', float, 0.2, minValue = 0.0),
        ParameterInfo('Linear_perturbance', u'k<sub>532,\u22a5</sub> =',
            'linear532C', float, 0.2, minValue = 0.0),
        ParameterHeader('Linear_perturbance', 'Common linear factor:'),
        ParameterInfo('Linear_perturbance', 'a =',
            'linearCommon', float, 1.0, minValue = 0.0),

        # ---- Concentration perturbance ----
        ParameterHeader('Concentration_perturbance', 'Total concentrations:'),
        ParameterInfo('Concentration_perturbance', u'\u03a9<sub>fine</sub> =',
            'concentrationFine', float, 0.05,
            minValue = 0.0, maxValue = 1.0),
        ParameterInfo('Concentration_perturbance',
            u'\u03a9<sub>coarse</sub> =',
            'concentrationCoarse', float, 0.05,
            minValue = 0.0, maxValue = 1.0),
        ParameterHeader('Concentration_perturbance', 'Sphericity:'),
        ParameterInfo('Concentration_perturbance',
            u'\u03a9<sub>sphericity</sub> =',
            'concentrationSphericity', float, 0.05,
            minValue = 0.0, maxValue = 1.0),

        # ---- Phase function perturbance ----
        ParameterHeader('Phase_function_perturbance', 'Fine mode:'),
        ParameterInfo('Phase_function_perturbance', 'f<sub>1 (355)</sub> =',
            'phaseF11Fine355', float, 0.2, minValue = 0.0),
        ParameterInfo('Phase_function_perturbance', 'f<sub>2 (532)</sub> =',
            'phaseF11Fine532', float, 0.2, minValue = 0.0),
        ParameterInfo('Phase_function_perturbance', 'f<sub>3 (1064)</sub> =',
            'phaseF11Fine1064', float, 0.2, minValue = 0.0),

        ParameterHeader('Phase_function_perturbance', 'Coarse total mode:'),
        ParameterInfo('Phase_function_perturbance', 'f<sub>4 (355)</sub> =',
            'phaseF11Coarse355', float, 0.2, minValue = 0.0),
        ParameterInfo('Phase_function_perturbance', 'f<sub>5 (532)</sub> =',
            'phaseF11Coarse532', float, 0.2, minValue = 0.0),
        ParameterInfo('Phase_function_perturbance', 'f<sub>6 (1064)</sub> =',
            'phaseF11Coarse1064', float, 0.2, minValue = 0.0),

        ParameterHeader('Phase_function_perturbance',
            'Coarse spherical mode:'),
        ParameterInfo('Phase_function_perturbance', 'f<sub>7 (355)</sub> =',
            'phaseF11Spherical355', float, 0.2, minValue = 0.0),
        ParameterInfo('Phase_function_perturbance', 'f<sub>8 (532)</sub> =',
            'phaseF11Spherical532', float, 0.2, minValue = 0.0),
        ParameterInfo('Phase_function_perturbance', 'f<sub>9 (1064)</sub> =',
            'phaseF11Spherical1064', float, 0.2, minValue = 0.0),

        ParameterHeader('Phase_function_perturbance', 'Coarse spheroid mode:'),
        ParameterInfo('Phase_function_perturbance', 'f<sub>10 (355)</sub> =',
            'phaseF11Spheroid355', float, 0.2, minValue = 0.0),
        ParameterInfo('Phase_function_perturbance', 'f<sub>11 (532)</sub> =',
            'phaseF11Spheroid532', float, 0.2, minValue = 0.0),
        ParameterInfo('Phase_function_perturbance', 'f<sub>13 (1064)</sub> =',
            'phaseF11Spheroid1064', float, 0.2, minValue = 0.0),
        ParameterInfo('Phase_function_perturbance',
            u'f<sub>12 (532,\u22a5)</sub> = ',
            'phaseF22Spheroid532', float, 0.2, minValue = 0.0),

        ParameterHeader('Phase_function_perturbance', 'Common factor:'),
        ParameterInfo('Phase_function_perturbance', 'q = ',
            'phaseCommon', float, 1.0, minValue = 0.0),
    ]

    # ---- Public overridden methods ------------------------------------------
    @classmethod
    def getParameterList(cls):
        return cls.parameterList

    @classmethod
    def getSettingsFilePath(cls):
        return 'settings/LiricPerturbanceParams.ini'

# *****************************************************************************
class LiricPerturbanceParamsDialog(ParamsDialog):
    """Dialog for interactive modification of a 'LiricPerturbanceParams'
    instance."""

    # ---- Private overridden methods -----------------------------------------
    @classmethod
    def getGroupInfoList(cls):

        return [
            ParameterGroupInfo('Global_switch', ''),

            ParameterGroupInfo('Number_of_evaluations',
                '&Number of evaluations'),
            ParameterGroupInfo('White_noise', '&White noise'),
            ParameterGroupInfo('Linear_perturbance', '&Linear perturbance'),

            ParameterGroupInfo('Phase_function_perturbance',
                '&Phase function perturbance', True),
            ParameterGroupInfo('Concentration_perturbance',
                '&Concentration perturbance', True),

        ]

    @classmethod
    def getWindowTitle(cls):
        return 'LIRIC perturbance options'

    # ---- Private overridden methods -----------------------------------------
    def updateEditEnableStatus(self):
        """Disable parameter editing if 'perturbanceEnabled' is 'False'."""

        isPerturbanceEnabled = self.getValue('perturbanceEnabled')

        for attributeName in self.editWidgets:
            if attributeName != 'perturbanceEnabled':
                self.setEnabled(attributeName, isPerturbanceEnabled)

    def updateCustomErrorMessages(self):

        self.updateFactorOverflowMessages('linear', 'linearCommon', 'a')
        self.updateFactorOverflowMessages('phase', 'phaseCommon', 'q')

    # ---- Private methods ----------------------------------------------------
    def updateFactorOverflowMessages(self, specificAttrPrefix, commonAttrName,
        commonDisplayName):
        """Check if parameters starting with 'specificAttrPrefix' are smaller
        than 1.0 when multiplied by the given common factor parameter, and set
        the error messages appropriately if they aren't."""

        commonValue = self.getValue(commonAttrName)
        if commonValue is None:
            return

        for attributeName in self.editWidgets:
            # Don't check the value of the common factor itself.
            if (attributeName.startswith(specificAttrPrefix) and
                attributeName != commonAttrName):

                specificValue = self.getValue(attributeName)

                if (specificValue is not None and
                    specificValue * commonValue >= 1.0):
                    self.setErrorMessage(attributeName,
                        'This value, when multiplied by the common factor %s, '
                        'must be smaller than 1' %
                        txt.quote(commonDisplayName, addQuotes = False))
