from PyQt5.QtWidgets import QLabel, QWidget, QGridLayout, QCheckBox, QGroupBox
from InftyDoubleSpinBox import InftyDoubleSpinBox
from PyQt5.QtCore import pyqtSignal, Qt
import helplib as hl
import numpy as np

class dataControlWidget(QGroupBox):
    showErrorBars_changed = pyqtSignal(bool)
    ignoreFirstPoint_changed = pyqtSignal(bool)
    data_changed = pyqtSignal(bool, bool)
    data_shift = pyqtSignal(np.float64)
    load_fits = pyqtSignal(list)
    load_view = pyqtSignal(str)
    load_meta = pyqtSignal(str)
    fit_on_startup = pyqtSignal()
    
    SHOW_ERROR_BARS = "Show error bars"
    SHOW_ERROR_BARS_NOT_LOADED = "Show error bars (could not be calculated)"
    
    def __init__(self):
        QWidget.__init__(self)

        self.setTitle('Data Settings')

        self.__lblEnergyShift = QLabel("Energy Shift:")
        self.__dsbEnergyShift = InftyDoubleSpinBox()
        self.__dsbEnergyShift.editingFinished.connect(self.__energyShiftChanged)
        self.__dsbEnergyShift.setSingleStep(0.01)
        
        self.__chkShowErrorBars = QCheckBox(self.SHOW_ERROR_BARS_NOT_LOADED)
        self.__chkShowErrorBars.stateChanged.connect(self.__chkShowErrorBars_changed)

        self.__chkIgnoreFirstPoint = QCheckBox('Ignore first data point.')
        self.__chkIgnoreFirstPoint.stateChanged.connect(self.__chkIgnoreFirstPoint_changed)
        
        self.__mainLayout = QGridLayout()
        self.setLayout(self.__mainLayout)
        self.__mainLayout.setAlignment(Qt.AlignTop)

        self.__mainLayout.addWidget(self.__lblEnergyShift, 0, 0)
        self.__mainLayout.addWidget(self.__dsbEnergyShift, 0, 1)

        self.__mainLayout.addWidget(self.__chkShowErrorBars, 1, 0, 1, 2)

        self.__mainLayout.addWidget(self.__chkIgnoreFirstPoint, 2, 0, 1, 2)
        self.__chkIgnoreFirstPoint.setVisible(False)
        
        self.reset(False)
    
    def reset(self, enable):
        self.__data = None
        self.__all_data = None
        self.__stdErrors = None
        
        self.__chkShowErrorBars.setCheckable(True)
        self.__chkShowErrorBars.setChecked(False)
        self.__chkShowErrorBars.setEnabled(False)

        self.__chkIgnoreFirstPoint.setCheckable(True)
        self.__chkIgnoreFirstPoint.setChecked(False)
        self.__chkIgnoreFirstPoint.setEnabled(False)

        self.setEnergyShift(0.0)
        self.__prevShift = 0.0
        
        self.setEnabled(enable)
    
    def __chkShowErrorBars_changed(self, state):
        self.__chkShowErrorBars.setCheckState(state)
        self.showErrorBars_changed.emit(self.getShowErrorBars())

    def __chkIgnoreFirstPoint_changed(self, state):
        self.__chkIgnoreFirstPoint.setCheckState(state)
        self.ignoreFirstPoint_changed.emit(self.getIgnoreFirstPoint())
    
    def __energyShiftChanged(self):
        self.cause_shift()

    def cause_shift(self):
        energyShift = self.__dsbEnergyShift.value()

        increment = energyShift - self.__prevShift

        self.__prevShift = energyShift

        self.data_shift.emit(increment)
        self.data_changed.emit(self.getShowErrorBars(), self.getIgnoreFirstPoint())

    #  def setData(self, data):
    #    self.__data = data

    def getData(self):

        first_point = 0

        if self.getIgnoreFirstPoint():
            first_point = 1

        return self.__data[first_point:,]

    def getEnergyShift(self):
        return (self.__dsbEnergyShift.value())

    def setEnergyShift(self, value):
        #increment = self.__dsbEnergyShift.value() - value
        increment = value - self.__dsbEnergyShift.value()
        self.__dsbEnergyShift.setValue(value)

        #self.__shiftData(increment)
        #self.data_shift.emit(increment)

    def __shiftData(self, increment):
        try:
            if self.__data is not None:
                for set in self.__data:
                    set[0] += increment
        except Exception as e:
            print(e)

    def getStdErrors(self):
        if self.__stdErrors is not None:
            first_point = 0

            if self.getIgnoreFirstPoint():
                first_point = 1

            return self.__stdErrors[first_point:]
        else:
            return None

    def getMax_Energy(self):
        if self.getData() is not None:
            return self.getData()[-1][0]
        else:
            return None

    def getMin_Energy(self):
        if self.getData() is not None:
            return self.getData()[0][0]
        else:
            return None
    
    def getShowErrorBars(self):
        return self.__chkShowErrorBars.isChecked()

    def setShowErrorBars(self, value):
        self.__chkShowErrorBars.setChecked(value)

    def getIgnoreFirstPoint(self):
        return self.__chkIgnoreFirstPoint.isChecked()

    def setIgnoreFirstPoint(self, value):
        self.__chkIgnoreFirstPoint.setChecked(value)
    
    def hasStdErrors(self):
        return self.__stdErrors is not None

    def loadFile(self, fileName, id_string):
        self.__all_data, self.__stdErrors, (fit_strings, view_string, data_string, meta_string), id_found =\
            hl.readFileForFitsDataAndStdErrorAndMetaData(fileName, id_string)

        #we need a copy to not save any altered data!
        self.__data = (self.__all_data[:, 0:2]).copy()

        if len(self.__data) <= 1:
            raise Exception("Not enough data in file!")
        
        if self.hasStdErrors():
            self.__chkShowErrorBars.setText(self.SHOW_ERROR_BARS)
        else:
            self.__chkShowErrorBars.setText(self.SHOW_ERROR_BARS_NOT_LOADED)
        
        self.__chkShowErrorBars.setEnabled(self.hasStdErrors())
        self.__chkShowErrorBars.setChecked(self.hasStdErrors())

        self.__chkIgnoreFirstPoint.setEnabled(True)

        self.data_changed.emit(self.hasStdErrors(), self.getIgnoreFirstPoint())
        self.load_fits.emit(fit_strings)
        self.load_view.emit(view_string)
        self.load_meta.emit(meta_string)

        self.load_from_data_string(data_string)
        self.cause_shift()

        self.fit_on_startup.emit()

        return id_found

    def load_from_data_string(self, data_string):
        if data_string is not None:
            split_string = data_string.split('\v')
            
            for i in range(0, len(split_string)):
                item = split_string[i].split('=')
                
                if len(item) == 2:
                    if (item[0] == 'egs'):
                        self.setEnergyShift(np.float64(item[1]))
                    elif item[0] == 'seb':
                        if item[1] == '1' or item[1] == 'True':
                            self.setShowErrorBars(True)
                        elif item[1] == '0' or item[1] == 'False':
                            self.setShowErrorBars(False)
                    elif item[0] == 'ifd':
                        if item[1] == '1' or item[1] == 'True':
                            self.setIgnoreFirstPoint(True)
                        elif item[1] == '0' or item[1] == 'False':
                            self.setIgnoreFirstPoint(False)

    def get_data_string(self):
        return 'egs=' + str(self.getEnergyShift()) + '\vseb=' + str(self.getShowErrorBars()) +\
               '\vifd=' + str(self.getIgnoreFirstPoint())
    
    def saveFile(self, fileName, id_string, fit_strings, view_string, data_string, meta_string):
        hl.saveFilewithMetaData(id_string, fileName, self.__all_data, (fit_strings, view_string, data_string, meta_string))

[((8, 28, 8, 44), 'PyQt5.QtCore.pyqtSignal', 'pyqtSignal', ({(8, 39, 8, 43): 'bool'}, {}), '(bool)', False, 'from PyQt5.QtCore import pyqtSignal, Qt\n'), ((9, 31, 9, 47), 'PyQt5.QtCore.pyqtSignal', 'pyqtSignal', ({(9, 42, 9, 46): 'bool'}, {}), '(bool)', False, 'from PyQt5.QtCore import pyqtSignal, Qt\n'), ((10, 19, 10, 41), 'PyQt5.QtCore.pyqtSignal', 'pyqtSignal', ({(10, 30, 10, 34): 'bool', (10, 36, 10, 40): 'bool'}, {}), '(bool, bool)', False, 'from PyQt5.QtCore import pyqtSignal, Qt\n'), ((11, 17, 11, 39), 'PyQt5.QtCore.pyqtSignal', 'pyqtSignal', ({(11, 28, 11, 38): 'np.float64'}, {}), '(np.float64)', False, 'from PyQt5.QtCore import pyqtSignal, Qt\n'), ((12, 16, 12, 32), 'PyQt5.QtCore.pyqtSignal', 'pyqtSignal', ({(12, 27, 12, 31): 'list'}, {}), '(list)', False, 'from PyQt5.QtCore import pyqtSignal, Qt\n'), ((13, 16, 13, 31), 'PyQt5.QtCore.pyqtSignal', 'pyqtSignal', ({(13, 27, 13, 30): 'str'}, {}), '(str)', False, 'from PyQt5.QtCore import pyqtSignal, Qt\n'), ((14, 16, 14, 31), 'PyQt5.QtCore.pyqtSignal', 'pyqtSignal', ({(14, 27, 14, 30): 'str'}, {}), '(str)', False, 'from PyQt5.QtCore import pyqtSignal, Qt\n'), ((15, 21, 15, 33), 'PyQt5.QtCore.pyqtSignal', 'pyqtSignal', ({}, {}), '()', False, 'from PyQt5.QtCore import pyqtSignal, Qt\n'), ((21, 8, 21, 30), 'PyQt5.QtWidgets.QWidget.__init__', 'QWidget.__init__', ({(21, 25, 21, 29): 'self'}, {}), '(self)', False, 'from PyQt5.QtWidgets import QLabel, QWidget, QGridLayout, QCheckBox, QGroupBox\n'), ((25, 32, 25, 55), 'PyQt5.QtWidgets.QLabel', 'QLabel', ({(25, 39, 25, 54): '"""Energy Shift:"""'}, {}), "('Energy Shift:')", False, 'from PyQt5.QtWidgets import QLabel, QWidget, QGridLayout, QCheckBox, QGroupBox\n'), ((26, 32, 26, 52), 'InftyDoubleSpinBox.InftyDoubleSpinBox', 'InftyDoubleSpinBox', ({}, {}), '()', False, 'from InftyDoubleSpinBox import InftyDoubleSpinBox\n'), ((30, 34, 30, 76), 'PyQt5.QtWidgets.QCheckBox', 'QCheckBox', ({(30, 44, 30, 75): 'self.SHOW_ERROR_BARS_NOT_LOADED'}, {}), '(self.SHOW_ERROR_BARS_NOT_LOADED)', False, 'from PyQt5.QtWidgets import QLabel, QWidget, QGridLayout, QCheckBox, QGroupBox\n'), ((33, 37, 33, 74), 'PyQt5.QtWidgets.QCheckBox', 'QCheckBox', ({(33, 47, 33, 73): '"""Ignore first data point."""'}, {}), "('Ignore first data point.')", False, 'from PyQt5.QtWidgets import QLabel, QWidget, QGridLayout, QCheckBox, QGroupBox\n'), ((36, 28, 36, 41), 'PyQt5.QtWidgets.QGridLayout', 'QGridLayout', ({}, {}), '()', False, 'from PyQt5.QtWidgets import QLabel, QWidget, QGridLayout, QCheckBox, QGroupBox\n'), ((160, 12, 160, 77), 'helplib.readFileForFitsDataAndStdErrorAndMetaData', 'hl.readFileForFitsDataAndStdErrorAndMetaData', ({(160, 57, 160, 65): 'fileName', (160, 67, 160, 76): 'id_string'}, {}), '(fileName, id_string)', True, 'import helplib as hl\n'), ((216, 8, 216, 123), 'helplib.saveFilewithMetaData', 'hl.saveFilewithMetaData', ({(216, 32, 216, 41): 'id_string', (216, 43, 216, 51): 'fileName', (216, 53, 216, 68): 'self.__all_data', (216, 70, 216, 122): '(fit_strings, view_string, data_string, meta_string)'}, {}), '(id_string, fileName, self.__all_data, (fit_strings,\n    view_string, data_string, meta_string))', True, 'import helplib as hl\n'), ((199, 44, 199, 63), 'numpy.float64', 'np.float64', ({(199, 55, 199, 62): 'item[1]'}, {}), '(item[1])', True, 'import numpy as np\n')]