class Serafin:
    """!
    @brief A Serafin object corresponds to a single Serafin in file IO stream

    # Attributes:
    - language <str>: language for variables ('fr' or 'en')
    - mode <str>: file open mode
    - file <_io.BufferedReader>: input Serafin stream
    - filename <str>: path to file
    - file_size <int>: size of file
    """
    def __init__(self, filename, mode, language):
        self.language = language
        self.mode = mode

        self.file = None  # will be opened when called using `with` statement
        self.filename = filename
        self.file_size = None

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()
        return False class VolumeCalculator:
    """!
    Compute volumes inside polygons from a Serafin input stream
    """

    NET_STRICT, NET, POSITIVE = 0, 1, 2
    INIT_VALUE = '+'  # special variable ID for the option 'Initial values of the first variable'

    def __init__(self, volume_type, var_ID, second_var_ID, input_stream, polynames, polygons,
                 time_sampling_frequency):
        self.volume_type = volume_type
        self.input_stream = input_stream
        self.polynames = polynames
        self.polygons = polygons

        self.var_ID = var_ID
        self.second_var_ID = second_var_ID

        self.time_indices = range(0, len(input_stream.time), time_sampling_frequency)

        self.mesh = None
        self.weights = []

        self.init_values = None
        if self.second_var_ID == VolumeCalculator.INIT_VALUE:
            self.init_values = input_stream.read_var_in_frame(0, self.var_ID)

    def construct_triangles(self, iter_pbar=lambda x, unit: x):
        self.mesh = TruncatedTriangularPrisms(self.input_stream.header, True, iter_pbar)

    def construct_weights(self, iter_pbar=lambda x, unit: x):
        """!
        Construct the point weights/intersections etc. depending on the volume type, for every polygons
        """
        if self.volume_type == VolumeCalculator.NET_STRICT:
            for poly in iter_pbar(self.polygons, unit='polygons'):
                self.weights.append(self.mesh.polygon_intersection_strict(poly))
        elif self.volume_type == VolumeCalculator.NET:
            for poly in iter_pbar(self.polygons, unit='polygons'):
                weight, triangle_polygon_intersection = self.mesh.polygon_intersection(poly)
                self.weights.append((weight, triangle_polygon_intersection))
        elif self.volume_type == VolumeCalculator.POSITIVE:
            for poly in iter_pbar(self.polygons, unit='polygons'):
                self.weights.append(self.mesh.polygon_intersection_all(poly))

    def volume_in_frame_in_polygon(self, weight, values, polygon):
        """!
        @brief Do the volume computation in a single frame, depending on the volume type
        @param weight <tuple>: the point weights/intersections etc. depending on the polygon and on the volume type
        @param values <numpy.1D-array>: the values of the variable for which the volume will be computed
        @param polygon <geom.geometry.Polygon>: the polygon in which the volume will be computed
        @return <float>: The value of the volume
        """
        if self.volume_type == VolumeCalculator.NET_STRICT:
            return weight.dot(values)
        elif self.volume_type == VolumeCalculator.NET:
            strict_weight, triangle_polygon_intersection = weight
            volume_inside = strict_weight.dot(values)
            volume_boundary = TruncatedTriangularPrisms.boundary_volume_in_polygon(triangle_polygon_intersection, values)
            return volume_inside + volume_boundary
        else:
            strict_weight, triangle_polygon_net_intersection, triangles, triangle_polygon_intersection = weight
            volume_net = strict_weight.dot(values)
            volume_net += TruncatedTriangularPrisms.boundary_volume_in_polygon(triangle_polygon_net_intersection, values)

            volume_positive = 0
            for a, b, c in triangles:
                vertices, area = triangles[a, b, c]
                volume_positive += TruncatedTriangularPrisms.superior_prism_volume(vertices, area, values[[a, b, c]])
            for a, b, c in triangle_polygon_intersection:
                vertices, area, intersection = triangle_polygon_intersection[a, b, c]
                volume_positive += TruncatedTriangularPrisms.superior_prism_volume_in_intersection(polygon, vertices,
                                                                                                   area, intersection,
                                                                                                   values[[a, b, c]])
            return volume_net, volume_positive, volume_net - volume_positive

    def read_values_in_frame(self, time_index):
        """!
        Read variable values in a single frame, depending on the first/second variable choice
        """
        values = self.input_stream.read_var_in_frame(time_index, self.var_ID)
        if self.second_var_ID is not None:
            if self.second_var_ID == VolumeCalculator.INIT_VALUE:
                values -= self.init_values
            else:
                second_values = self.input_stream.read_var_in_frame(time_index, self.second_var_ID)
                values -= second_values
        return values

    def run(self, fmt_float=settings.FMT_FLOAT):
        """!
        Separate the major part of the computation, allowing a GUI override
        """
        result = []
        for time_index in self.time_indices:
            i_result = [str(self.input_stream.time[time_index])]
            values = self.read_values_in_frame(time_index)

            for j in range(len(self.polygons)):
                weight = self.weights[j]
                volume = self.volume_in_frame_in_polygon(weight, values, self.polygons[j])
                if self.volume_type == VolumeCalculator.POSITIVE:
                    for v in volume:
                        i_result.append(fmt_float.format(v))
                else:
                    i_result.append(fmt_float.format(volume))
            result.append(i_result)
        return result

    def get_csv_header(self):
        header = ['time']
        if self.volume_type == VolumeCalculator.POSITIVE:
            for name in self.polynames:
                header.append(name)
                header.append(name + ' POSITIVE')
                header.append(name + ' NEGATIVE')
        else:
            for name in self.polynames:
                header.append(name)
        return header

    def write_csv(self, result, output_stream, separator):
        output_stream.write(separator.join(self.get_csv_header()))
        output_stream.write('\n')

        for line in result:
            output_stream.write(separator.join(line))
            output_stream.write('\n') class LoadMeshDialog(OutputProgressDialog):
    def __init__(self, mesh_type, input_header):
        super().__init__('Processing the mesh. Please wait.', 'Processing the mesh...')
        thread = ConstructIndexThread(mesh_type, input_header)
        self.connectToThread(thread)

    def outputFinished(self):
        self.setValue(100)
        self.setCancelButtonText('OK')
        logging.info('Finished processing the mesh')

    def cancel(self):
        if self.cancelButton.text() == 'Cancel':
            if not self.thread.canceled:
                self.thread.canceled = True
                logging.info('Input canceled.')

    def run(self):
        self.thread.run()
        if not self.thread.canceled:
            self.outputFinished()
        self.exec_()
        return self.thread.mesh class MapViewer(QWidget):
    def __init__(self, canvas):
        super().__init__()
        self.canvas = canvas

        # add the the tool bar
        self.toolBar = NavigationToolbar2QT(self.canvas, self)
        self.toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        self.scrollArea = QScrollArea()
        self.scrollArea.setBackgroundRole(QPalette.Dark)
        self.scrollArea.setWidget(self.canvas)

        self._setLayout()
        self.resize(800, 700)

    def _setLayout(self):
        vlayout = QVBoxLayout()
        vlayout.addWidget(self.toolBar)
        vlayout.addWidget(self.scrollArea)
        vlayout.setSpacing(0)
        vlayout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(vlayout)

        self.setWindowTitle('Map Viewer')
        self.resize(self.sizeHint()) def open_polygons():
    filename, _ = QFileDialog.getOpenFileName(None, 'Open a .i2s or .shp file', '', 'Line sets (*.i2s *.shp)',
                                              options=QFileDialog.Options() | QFileDialog.DontUseNativeDialog)
    if not filename:
        return False, '', []
    if not test_open(filename):
        return False, '', []

    polygons = []
    if filename.endswith('.i2s'):
        with BlueKenue.Read(filename) as f:
            f.read_header()
            for i, poly in enumerate(f.get_polygons()):
                poly.set_id('Polygon %i' % i)
                polygons.append(poly)
    else:
        try:
            for i, poly in enumerate(Shapefile.get_polygons(filename)):
                poly.set_id('Polygon %i' % i)
                polygons.append(poly)
        except ShapefileException as e:
            QMessageBox.critical(None, 'Error', e, QMessageBox.Ok)
            return False, '', []
    if not polygons:
        QMessageBox.critical(None, 'Error', 'The file does not contain any polygon.',
                             QMessageBox.Ok)
        return False, '', []
    return True, filename, polygons class OutputProgressDialog(QProgressDialog):
    def __init__(self, message='Output in progress', title='Writing the output...', parent=None):
        super().__init__(message, 'OK', 0, 100, parent)
        self.setMinimumDuration(0)

        self.cancelButton = QPushButton('Cancel')
        self.setCancelButton(self.cancelButton)
        self.canceled.connect(self.cancel)

        self.setAutoReset(False)
        self.setAutoClose(False)

        self.setWindowTitle(title)
        self.setWindowFlags(Qt.WindowTitleHint)
        self.setFixedSize(300, 150)
        self.thread = None

        self.open()
        self.setValue(0)
        QApplication.processEvents()

    def outputFinished(self):
        self.setValue(100)
        self.setCancelButtonText('OK')
        logging.info('Finished writing the output.')

    def connectToThread(self, thread):
        self.thread = thread
        thread.tick.connect(self.setValue)

    def cancel(self):
        if self.cancelButton.text() == 'Cancel':
            if not self.thread.canceled:
                self.thread.canceled = True
                logging.info('Output canceled.') class OutputThread(QThread):
    tick = pyqtSignal(int, name='changed')

    def __init__(self):
        super().__init__()
        self.canceled = False class PolygonMapCanvas(MapCanvas):
    def __init__(self):
        super().__init__()
        self.PINK = '#fcabbd'

    def reinitFigure(self, mesh, polygons, polynames):
        # draw the mesh
        self.initFigure(mesh)

        # add the polygons to the map
        patches = []
        for p in polygons:
            patches.append(PolygonPatch(p.polyline().buffer(0), fc=self.PINK, ec=self.BLACK, alpha=0.5, zorder=1))
        self.axes.add_collection(PatchCollection(patches, match_original=True))

        # add polygon labels
        for p, name in zip(polygons, polynames):
            center = p.polyline().centroid
            cx, cy = center.x, center.y
            self.axes.annotate(name, (cx, cy), color='k', weight='bold',
                               fontsize=8, ha='center', va='center')
        self.draw() class ProgressBarIterator:
    def __init__(self, iterable, emit=lambda x: x, perc_range=(0, 100), length=None):
        """
        Update progress bar during an iterative
        @param iterable: iterator
        @param perc_range <(int, int)>: minimum and maximum percentage bounds
        @param emit: function to call at each significant progress
        """
        self.emit = emit
        self.iterable = iterable
        self.min, self.max = perc_range
        self.length = length

    def do_at_next(self, perc):
        """
        Call self.emit function with curent percentage
        @param perc <float>: percentage progress (within range [0, 100])
        """
        self.emit(perc)
        QApplication.processEvents()

    def __iter__(self):
        """Iterate and update progress bar at each new percentage"""
        length = len(self.iterable) if self.length is None else self.length
        if length != 0:
            ratio = (self.max - self.min) / length
            old_perc = -1
            for i, value in enumerate(self.iterable):
                yield value

                new_perc = int(self.min + (i + 1) * ratio)
                if new_perc > old_perc:
                    self.do_at_next(new_perc)
                old_perc = new_perc

    @staticmethod
    def prepare(*args, **kwargs):
        """
        Get a ready sub-class on which to iterate
        @return <SubProgressBarIterator>:  ProgressBarIterator sub-class with pre-defined arguments
        """
        class SubProgressBarIterator(ProgressBarIterator):
            def __init__(self, iterable, unit=None):
                """!
                @param iterable: iterable or generator to loop over
                @param unit: argument not used in GUI
                """
                super().__init__(iterable, *args, **kwargs)
        return SubProgressBarIterator class PyTelToolWidget(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent
        self.input = None
        if parent is None:
            self.language = settings.LANG
            self.csv_separator = settings.CSV_SEPARATOR
            self.fmt_float = settings.FMT_FLOAT
            self.logging_level = settings.LOGGING_LEVEL
        else:
            self.language = parent.language
            self.csv_separator = parent.csv_separator
            self.fmt_float = parent.fmt_float
            self.logging_level = parent.logging_level
        self.setMinimumWidth(600)
        self.setWindowFlags(self.windowFlags() | Qt.CustomizeWindowHint)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    def inDialog(self):
        if self.parent is not None:
            self.parent.inDialog()
        else:
            self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint)
            self.setEnabled(False)
            self.show()

    def outDialog(self):
        if self.parent is not None:
            self.parent.outDialog()
        else:
            self.setWindowFlags(self.windowFlags() | Qt.WindowCloseButtonHint)
            self.setEnabled(True)
            self.show()

    def switch_language(self, language):
        if language == 'fr':
            self.input.frenchButton.setChecked(True)
        else:
            self.input.englishButton.setChecked(True) def read_csv(filename, separator):
    data = {}
    with open(filename, 'r') as f:
        headers = f.readline().rstrip().split(separator)
        for header in headers:
            data[header] = []
        for line in f.readlines():
            items = line.rstrip().split(separator)
            for header, item in zip(headers, items):
                data[header].append(float(item))
        for header in headers:
            data[header] = np.array(data[header])
    return data, headers def save_dialog(file_format, input_name='', input_names=None):
    # create the save file dialog
    options = QFileDialog.Options()
    options |= QFileDialog.DontUseNativeDialog
    options |= QFileDialog.DontConfirmOverwrite
    if file_format == 'Serafin':
        extensions = settings.SERAFIN_EXT
        file_filter = 'Serafin Files (%s)' % ' '.join(['*%s' % extension for extension in extensions])
    elif file_format == 'CSV':
        extensions = ['.csv']
        file_filter = 'CSV Files (*.csv)'
    else:
        raise NotImplementedError('File format %s is not supported' % file_format)
    filename, _ = QFileDialog.getSaveFileName(None, 'Choose the output file name', '', file_filter, options=options)

    # check the file name consistency
    if not filename:
        return True, ''

    # add default extension (taken as first) if missing
    if os.path.splitext(filename)[1] not in extensions:
        filename += extensions[0]

    # overwrite to the input file is forbidden
    if input_name:
        if filename == input_name:
            QMessageBox.critical(None, 'Error', 'Cannot overwrite to the input file.', QMessageBox.Ok)
            return True, ''
    elif input_names:
        for name in input_names:
            if filename == name:
                QMessageBox.critical(None, 'Error', 'Cannot overwrite to the input file.', QMessageBox.Ok)
                return True, ''

    # handle overwrite manually
    overwrite = handle_overwrite(filename)
    if overwrite is None:
        return True, ''

    return False, filename class SerafinInputTab(QWidget):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent

        # create the button open
        self.btnOpen = QPushButton('Open', self, icon=self.style().standardIcon(QStyle.SP_DialogOpenButton))
        self.btnOpen.setToolTip('<b>Open</b> a Serafin file')
        self.btnOpen.setFixedSize(105, 50)

        # create some text fields displaying the IO files info
        self.inNameBox = QLineEdit()
        self.inNameBox.setReadOnly(True)
        self.summaryTextBox = QPlainTextEdit()
        self.summaryTextBox.setFixedHeight(50)
        self.summaryTextBox.setReadOnly(True)

        # create a checkbox for language selection
        self.langBox = QGroupBox('Input language')
        hlayout = QHBoxLayout()
        self.frenchButton = QRadioButton('French')
        self.englishButton = QRadioButton('English')
        hlayout.addWidget(self.frenchButton)
        hlayout.addWidget(self.englishButton)
        self.langBox.setLayout(hlayout)
        self.langBox.setMaximumHeight(80)
        if self.parent.language == 'fr':
            self.frenchButton.setChecked(True)
        else:
            self.englishButton.setChecked(True)

        # create the widget displaying message logs
        self.logTextBox = QPlainTextEditLogger(self)
        self.logTextBox.setFormatter(logging.Formatter(settings.LOGGING_FMT_GUI))
        logging.getLogger().addHandler(self.logTextBox)
        logging.getLogger().setLevel(self.parent.logging_level)

        self.input_layout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.setAlignment(Qt.AlignLeft)
        hlayout.addItem(QSpacerItem(50, 1))
        hlayout.addWidget(self.btnOpen)
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.langBox)
        self.input_layout.addLayout(hlayout)
        self.input_layout.addItem(QSpacerItem(10, 10))

        glayout = QGridLayout()
        glayout.addWidget(QLabel('Input file'), 1, 1)
        glayout.addWidget(self.inNameBox, 1, 2)
        glayout.addWidget(QLabel('Summary'), 2, 1)
        glayout.addWidget(self.summaryTextBox, 2, 2)
        glayout.setAlignment(Qt.AlignLeft)
        glayout.setSpacing(10)
        self.input_layout.addLayout(glayout)

    def current_language(self):
        if self.frenchButton.isChecked():
            return 'fr'
        return 'en'

    def reset(self):
        self.inNameBox.clear()
        self.summaryTextBox.clear()

    def open_event(self):
        filename, _ = QFileDialog.getOpenFileName(self, 'Open a Serafin file', '', 'Serafin Files (%s)' %
                                                  ' '.join(['*%s' % extension for extension in settings.SERAFIN_EXT]),
                                                  options=QFileDialog.Options() | QFileDialog.DontUseNativeDialog)
        if not filename:
            return True, ''

        if not test_open(filename):
            return True, ''

        return False, filename

    def read(self, filename):
        self.inNameBox.setText(filename)
        data = SerafinData('', filename, self.current_language())
        try:
            data.read()
        except (Serafin.SerafinRequestError, Serafin.SerafinValidationError) as e:
            QMessageBox.critical(None, 'Serafin Error', e.message, QMessageBox.Ok, QMessageBox.Ok)
            return False, None
        except PermissionError:
            QMessageBox.critical(None, 'Permission denied',
                                 'Permission denied. (Is the file opened by another application?).',
                                 QMessageBox.Ok, QMessageBox.Ok)
            return False, None
        self.summaryTextBox.appendPlainText(data.header.summary())
        logging.info('Finished reading the input file')
        return True, data

    def read_2d(self, filename, update=True):
        if update:
            self.inNameBox.setText(filename)
        data = SerafinData('', filename, self.current_language())

        try:
            is_2d = data.read()
        except (Serafin.SerafinRequestError, Serafin.SerafinValidationError) as e:
            QMessageBox.critical(None, 'Serafin Error', e.message, QMessageBox.Ok, QMessageBox.Ok)
            return False, None
        except PermissionError:
            QMessageBox.critical(None, 'Permission denied',
                                 'Permission denied. (Is the file opened by another application?).',
                                 QMessageBox.Ok, QMessageBox.Ok)
            return False, None

        if not is_2d:
            QMessageBox.critical(self, 'Error', 'The file type (TELEMAC 3D) is currently not supported.',
                                 QMessageBox.Ok)
            return False, None
        if update:
            self.summaryTextBox.appendPlainText(data.header.summary())
        logging.info('Finished reading the input file')
        return True, data class VolumePlotViewer(TemporalPlotViewer):
    def __init__(self):
        super().__init__('polygon')
        self.csv_separator = ''
        self.var_ID = None
        self.second_var_ID = None
        self.language = 'fr'

        self.setWindowTitle('Visualize the temporal evolution of volumes')

        self.poly_menu = QMenu('&Polygons', self)
        self.poly_menu.addAction(self.selectColumnsAct_short)
        self.poly_menu.addAction(self.editColumnNamesAct_short)
        self.poly_menu.addAction(self.editColumColorAct_short)

    def _defaultYLabel(self):
        word = {'fr': 'de', 'en': 'of'}[self.language]
        if self.second_var_ID == VolumeCalculator.INIT_VALUE:
            return 'Volume %s (%s - %s$_0$)' % (word, self.var_ID, self.var_ID)
        elif self.second_var_ID is None:
            return 'Volume %s %s' % (word, self.var_ID)
        return 'Volume %s (%s - %s)' % (word, self.var_ID, self.second_var_ID)

    def replot(self):
        self.canvas.axes.clear()
        for column in self.current_columns:
            self.canvas.axes.plot(self.time[self.timeFormat], self.data[column], '-', color=self.column_colors[column],
                                  linewidth=2, label=self.column_labels[column])
        self.canvas.axes.legend()
        self.canvas.axes.grid(linestyle='dotted')
        self.canvas.axes.set_xlabel(self.current_xlabel)
        self.canvas.axes.set_ylabel(self.current_ylabel)
        self.canvas.axes.set_title(self.current_title)
        if self.timeFormat in [1, 2]:
            self.canvas.axes.set_xticklabels(self.str_datetime if self.timeFormat == 1 else self.str_datetime_bis)
            for label in self.canvas.axes.get_xticklabels():
                label.set_rotation(45)
                label.set_fontsize(8)
        self.canvas.draw()
import datetime
import logging
import sys
from itertools import cycle
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QAction, QApplication, QCheckBox, QComboBox, QGridLayout, QHBoxLayout,
                             QLabel, QLineEdit, QMenu, QMessageBox, QPlainTextEdit, QPushButton,
                             QSpacerItem, QStyle, QTabWidget, QVBoxLayout)
from pyteltools.slf import Serafin
from pyteltools.slf.volume import VolumeCalculator
from .util import LoadMeshDialog, MapViewer, open_polygons, OutputProgressDialog, OutputThread, PolygonMapCanvas, \
    ProgressBarIterator, PyTelToolWidget, read_csv, save_dialog, SerafinInputTab, VolumePlotViewer
        glayout.addWidget(QLabel('     Select a variable to subtract (optional)'), 2, 1)
        glayout.addWidget(self.secondVarBox, 2, 2)
        glayout.addWidget(QLabel('     More options'), 3, 1)
        glayout.addWidget(self.supVolumeBox, 3, 2)
        hlayout = QHBoxLayout()
        hlayout.addWidget(QLabel('Time sampling frequency'))
        hlayout.addWidget(self.timeSampling)
        hlayout.setAlignment(self.timeSampling, Qt.AlignLeft)
        hlayout.addStretch()
        glayout.addLayout(hlayout, 4, 2)

        glayout.setAlignment(Qt.AlignLeft)
        glayout.setSpacing(10)
        mainLayout.addLayout(glayout)
        mainLayout.addItem(QSpacerItem(10, 20))

        hlayout = QHBoxLayout()
        hlayout.addItem(QSpacerItem(30, 1))
        hlayout.addWidget(self.btnSubmit)
        hlayout.addWidget(self.csvNameBox)
        mainLayout.addLayout(hlayout)
        mainLayout.addStretch()

        mainLayout.addItem(QSpacerItem(10, 15))
        mainLayout.addWidget(QLabel('   Message logs'))
        mainLayout.addWidget(self.logTextBox.widget)
        self.setLayout(mainLayout)

    def _checkSamplingFrequency(self):
        try:
            sampling_frequency = int(self.timeSampling.text())
        except ValueError:
            QMessageBox.critical(self, 'Error', 'The sampling frequency must be a number!',
                                 QMessageBox.Ok)
            self.timeSampling.setText('1')
            return
        if sampling_frequency < 1 or sampling_frequency > len(self.data.time):
            QMessageBox.critical(self, 'Error', 'The sampling frequency must be in the range [1; nbFrames]!',
                                 QMessageBox.Ok)
            self.timeSampling.setText('1')
            return

    def _reinitInput(self):
        self.reset()
        self.csvNameBox.clear()
        self.old_options = (self.timeSampling.text(),
                            self.firstVarBox.currentText(),
                            self.secondVarBox.currentText())
        self.timeSampling.setText('1')
        self.firstVarBox.clear()
        self.secondVarBox.clear()
        self.csvNameBox.clear()
        self.btnOpenPolygon.setEnabled(False)

    def _resetDefaultOptions(self):
        sampling_frequency, first_var, second_var = self.old_options
        if int(sampling_frequency) <= len(self.data.time):
            self.timeSampling.setText(sampling_frequency)
        var_ID = first_var.split('(')[0][:-1]
        if var_ID in self.data.header.var_IDs:
            self.firstVarBox.setCurrentIndex(self.data.header.var_IDs.index(var_ID))
        if '(' in second_var:
            var_ID = second_var.split('(')[0][:-1]
            if var_ID in self.data.header.var_IDs:
                self.secondVarBox.setCurrentIndex(2 + self.data.header.var_IDs.index(var_ID))
        elif second_var[:4] == 'Init':
            self.secondVarBox.setCurrentIndex(1)
        else:
            self.secondVarBox.setCurrentIndex(0)

    def btnOpenSerafinEvent(self):
        canceled, filename = super().open_event()
        if canceled:
            return

        self._reinitInput()

        success, data = self.read_2d(filename)
        if not success:
            return

        # record the mesh for future visualization and calculations
        self.parent.inDialog()
        meshLoader = LoadMeshDialog('volume', data.header)
        self.mesh = meshLoader.run()
        self.parent.outDialog()
        if meshLoader.thread.canceled:
            self.polygonNameBox.clear()
            self.summaryTextBox.clear()
            return

        self.data = data
        self.btnOpenPolygon.setEnabled(True)
        self.secondVarBox.addItem('0')
        self.secondVarBox.addItem('Initial values of the first variable')

        for var_ID, var_name in zip(self.data.header.var_IDs, self.data.header.var_names):
            self.firstVarBox.addItem(var_ID + ' (%s)' % var_name.decode(Serafin.SLF_EIT).strip())
            self.secondVarBox.addItem(var_ID + ' (%s)' % var_name.decode(Serafin.SLF_EIT).strip())

        self._resetDefaultOptions()

        self.parent.imageTab.reset()
        self.parent.tab.setTabEnabled(1, False)

    def btnOpenPolygonEvent(self):
        success, filename, polygons = open_polygons()
        if not success:
            return
        self.polygons = polygons
        logging.info('Finished reading the polygon file %s' % filename)
        self.polygonNameBox.clear()
        self.polygonNameBox.appendPlainText(filename + '\n' + 'The file contains {} polygon{}.'.format(
            len(self.polygons), 's' if len(self.polygons) > 1 else ''))
        self.csvNameBox.clear()
        self.btnSubmit.setEnabled(True)
        self.parent.imageTab.reset()
        self.parent.tab.setTabEnabled(1, False)

    def btnSubmitEvent(self):

        canceled, filename = save_dialog('CSV')