'''
/***************************************************************************
Name	   :  region_controller.py
Description:  Region controller class for FEWSTools plugin,
              updated from QGIS2
copyright  :  (C) 2019-2023 by FEWS
email      :  minxuansun@contractor.usgs.gov
Modified   :  08/14/2020 cholen - Fix regex check on comments, use utils
              08/29/2020 cholen - Add mask import functionality
              10/02/2020 cholen - Fix default index select
              02/23/2022 cholen - Codebase consistency changes.
              06/20/2022 jhowton - Added GeoWRSI region options
              08/30/2022 cholen - Remove DataDirectory attribute
              10/03/2024 jhowton - Improved import / export
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
'''
import configparser
import glob
import shutil
import os
import re
import zipfile

from qgis.core import QgsMessageLog, Qgis
from qgis.utils import iface

from PyQt5.QtWidgets import QMessageBox, QDialog, QFileDialog

from fews_tools import fews_tools_config as config
from fews_tools.utilities import geoclim_utilities as util

from fews_tools.controllers.new_name_controller import NewNameController
from fews_tools.controllers.get_spatial_extents_controller import GetSpatialExtentsController
from fews_tools.controllers.import_vector_to_raster_controller import ImportVectorToRasterController
from fews_tools.models.region_model import RegionModel
from fews_tools.models.workspace_setup_model import WorkspaceSetupModel
from fews_tools.forms.Ui_DefineRegion import Ui_DefineRegion


class RegionController(QDialog):
    '''
    Class for region definitions
    '''

    def __init__(self):
        QDialog.__init__(self)
        self.ui = Ui_DefineRegion()
        self.ui.setupUi(self)
        self.region_name_list = None

        # get a list to hold widget values
        self.widget_val_list = [''] * 11

        self.reg_info = RegionModel()
        self.reg_dic = None
        self.wrksp_setup = WorkspaceSetupModel()  # need to get paths

        self.map_files_loc = self.wrksp_setup.get_map_data_path()
        self.static_files_loc = self.wrksp_setup.get_static_data_path()
        self.climate_files_loc = self.wrksp_setup.get_climate_data_path()
        self.color_files_loc = self.wrksp_setup.get_colors_path()

        # will track changes to form for 'save'
        self.ui.commentLineEdit.textChanged.connect(self.save_enabled)
        self.ui.defaultRegComboBox.currentIndexChanged['QString'].connect(
            self.save_enabled)
        self.ui.minLatSpinBox.valueChanged.connect(self.save_enabled)
        self.ui.maxLatSpinBox.valueChanged.connect(self.save_enabled)
        self.ui.minLonSpinBox.valueChanged.connect(self.save_enabled)
        self.ui.maxLonSpinBox.valueChanged.connect(self.save_enabled)
        self.ui.cellWidthSpinBox.valueChanged.connect(self.save_enabled)
        self.ui.cellHeightSpinBox.valueChanged.connect(self.save_enabled)
        self.ui.maskLineEdit.textChanged.connect(self.save_enabled)
        self.ui.mapLineEdit.textChanged.connect(self.save_enabled)
        self.ui.map2LineEdit.textChanged.connect(self.save_enabled)
        self.ui.initialPeriodSpinBox.valueChanged.connect(self.save_enabled)
        self.ui.finalPeriodSpinBox.valueChanged.connect(self.save_enabled)
        self.ui.SOSLineEdit.textChanged.connect(self.save_enabled)
        self.ui.WRSILineEdit.textChanged.connect(self.save_enabled)
        self.ui.LGPLineEdit.textChanged.connect(self.save_enabled)
        self.ui.WHCLineEdit.textChanged.connect(self.save_enabled)
        self.ui.SOSColorLineEdit.textChanged.connect(self.save_enabled)

        # connect remaining widgets
        self.ui.regionComboBox.currentIndexChanged['QString'].connect(
            self.update_form_widgets_for_new_region_selection)
        self.ui.getExtentFromMapButton.clicked.connect(
            self.get_extent_from_map)
        self.ui.browseMapButton.clicked.connect(self.browse_map1_path)
        self.ui.browseMap2Button.clicked.connect(self.browse_map2_path)
        self.ui.browseMaskButton.clicked.connect(self.browse_mask_path)
        self.ui.saveButton.clicked.connect(self.save_region)
        self.ui.deleteButton.clicked.connect(self.delete_region)
        self.ui.newButton.clicked.connect(self.new_region)
        self.ui.copyRegionButton.clicked.connect(self.new_region_from_copy)
        self.ui.importButton.clicked.connect(self.import_region)
        self.ui.exportButton.clicked.connect(self.export_region)
        self.ui.importMapButton.clicked.connect(self.import_mask_from_shape)
        self.ui.geowrsiCheckBox.toggled.connect(self.geowrsi_toggled)
        self.ui.dekadalRadioButton.toggled.connect(self.period_changed)
        self.ui.browseSOSButton.clicked.connect(self.browse_sos_path)
        self.ui.browseWRSIButton.clicked.connect(self.browse_wrsi_path)
        self.ui.browseLGPButton.clicked.connect(self.browse_lgp_path)
        self.ui.browseWHCButton.clicked.connect(self.browse_whc_path)
        self.ui.browseSOSColorButton.clicked.connect(
            self.browse_sos_color_path)
        self.__initial_form_load__()

    def __check_new_name__(self, new_name):
        '''
        Check if name exists return err if yes
        :param new_name(string) - New name
        :return err(boolean) - True if name already exists, else False
        '''
        err = False
        self.region_name_list = self.reg_info.get_all_region_names()
        if new_name in self.region_name_list or \
                self.ui.regionComboBox.findText(new_name) != -1:
            err = True
            QMessageBox.critical(
                self, 'Error - Name already exists',
                'The selected name already exists in the database.',
                QMessageBox.Ok)
        return err

    def __check_required_widgets__(self):
        '''
        Check that required widgets are filled.
        :return err(boolean) - True if needed entry is missing, else False
        '''
        form_err = False
        req_combo_boxes = [self.ui.regionComboBox.currentText(),
                           self.ui.defaultRegComboBox.currentText()]
        req_line_edits = [self.ui.maskLineEdit.text(),
                          self.ui.mapLineEdit.text()]
        # verify that all required fields are filled:
        for entry in req_combo_boxes:
            if entry in (' ', ''):
                form_err = True
        for entry in req_line_edits:
            if entry == '':
                form_err = True
        return form_err

    def __check_wrsi__(self):
        '''
        Check if the required wrsi fields are filled if the checkbox is toggled
        '''
        wrsi_err = False
        req_line_edits = [self.ui.SOSLineEdit.text(),
                          self.ui.WRSILineEdit.text(),
                          self.ui.LGPLineEdit.text(),
                          self.ui.WHCLineEdit.text(),
                          self.ui.SOSColorLineEdit.text()]
        if self.ui.geowrsiCheckBox.isChecked():
            for entry in req_line_edits:
                if entry == '':
                    wrsi_err = True
        return wrsi_err

    def __initial_form_load__(self):
        '''
        Fills the form entries initial load
        '''
        util.fill_misc_widget(self.ui.defaultRegComboBox, ['No', 'Yes'])

        self.region_name_list = self.reg_info.get_all_region_names()
        self.region_name_list = sorted(self.region_name_list)
        util.fill_misc_widget(self.ui.regionComboBox, self.region_name_list)
        # get name for default region from db
        default_reg_name = self.reg_info.query_default_region_name()
        # changing the index
        # forces update_form_widgets_for_new_region_selection which fills form
        self.ui.regionComboBox.setCurrentIndex(
            self.ui.regionComboBox.findText(default_reg_name))

        self.ui.saveButton.setEnabled(False)

    def __validate_text_inputs__(self):
        '''
        Validate the free form text entries
        return err(boolean) - True if entry has an error, else False
        '''
        err = False
        checks = self.ui.commentLineEdit.text()
        # comments can be empty
        # but must not contain special chars or be too long
        for entry in checks:
            if len(entry) > config.MAX_CHARS or not\
                    re.match(config.REG_EXPR_COMMENTS, entry):
                err = True
        if err is True:
            QMessageBox.critical(
                self,
                'Error in form comments',
                'Comments may contain alpha-numeric characters,\n' +
                'underscores and dashes.\n' +
                'No other special characters are allowed!',
                QMessageBox.Ok)
        return err

    def browse_map_path(self, widget):
        '''
        Function to browse to map files.
        :param widget(LineEdit widget object) - The path widget
        '''
        map_file =\
            QFileDialog.getOpenFileName(self,
                                        'Please Select the Map File',
                                        self.map_files_loc,
                                        config.VEC_FILE_TYPES)
        if map_file[0] != '':
            widget.setText(
                self.wrksp_setup.fix_os_sep_in_path(map_file[0]))

    def browse_map1_path(self):
        '''
        Function to browse to map files.
        '''
        self.browse_map_path(self.ui.mapLineEdit)

    def browse_map2_path(self):
        '''
        Function to browse to alternate map files.
        '''
        self.browse_map_path(self.ui.map2LineEdit)

    def browse_static_path(self, widget):
        '''
        Function to browse to static files.
        :param widget(LineEdit widget object) - The path widget
        '''
        static_file =\
            QFileDialog.getOpenFileName(self,
                                        'Select Raster',
                                        self.static_files_loc,
                                        config.RST_FILE_TYPES)
        if static_file[0] != '':
            widget.setText(
                self.wrksp_setup.fix_os_sep_in_path(static_file[0]))

    def browse_mask_path(self):
        '''
        Function to browse to mask files.
        '''
        self.browse_static_path(self.ui.maskLineEdit)

    def browse_sos_color_path(self):
        '''
        Function to browse to SOSColor files.
        '''
        sos_color_file =\
            QFileDialog.getOpenFileName(self,
                                        'Please Select the SOS Color File',
                                        self.color_files_loc,
                                        'QML Files (*.qml)')
        if sos_color_file[0] != '':
            self.ui.SOSColorLineEdit.setText(
                self.wrksp_setup.fix_os_sep_in_path(sos_color_file[0]))

    def browse_sos_path(self):
        '''
        Function to browse to SOS files.
        '''
        self.browse_static_path(self.ui.SOSLineEdit)

    def browse_wrsi_path(self):
        '''
        Function to browse to Climatological WRSI files.
        '''
        self.browse_static_path(self.ui.WRSILineEdit)

    def browse_lgp_path(self):
        '''
        Function to browse to LGP files.
        '''
        self.browse_static_path(self.ui.LGPLineEdit)

    def browse_whc_path(self):
        '''
        Function to browse to WHC files.
        '''
        self.browse_static_path(self.ui.WHCLineEdit)

    def delete_region(self):
        '''
        Delete selected region from the database.
        '''
        reg_name = self.ui.regionComboBox.currentText()
        reply = QMessageBox.question(
            self,
            'Delete Region?',
            'Are you sure you want to delete the ' + reg_name + ' region?\n '
            'This cannot be undone.',
            QMessageBox.Yes, QMessageBox.Cancel)

        if reply == QMessageBox.Yes:
            self.reg_info.delete_region_record(reg_name)
            # need to fix the combo box
            self.ui.regionComboBox.removeItem(
                self.ui.regionComboBox.findText(reg_name))
            # reload the form
            show_region = self.reg_info.query_default_region_name()
            self.ui.regionComboBox.setCurrentIndex(
                self.ui.regionComboBox.findText(show_region))
            if reg_name in self.region_name_list:
                self.region_name_list.remove(reg_name)

    def get_extent_from_map(self):
        '''
        Fill in map extents from a selected map.
        '''
        extents_dlg = GetSpatialExtentsController()
        extents_dlg.exec_()
        extents = extents_dlg.get_extents()
        self.ui.minLatSpinBox.setValue(extents[0])
        self.ui.maxLatSpinBox.setValue(extents[1])
        self.ui.minLonSpinBox.setValue(extents[2])
        self.ui.maxLonSpinBox.setValue(extents[3])

    def get_widget_val_list(self):
        '''
        Get the widget values list
        '''
        return self.widget_val_list

    def import_mask_from_shape(self):
        '''
        Initiates the dialog to rasterize a vector into a mask file
        '''
        reg_dic = {
            'RegionName': self.ui.regionComboBox.currentText(),
            'MinimumLatitude': self.ui.minLatSpinBox.value(),
            'MaximumLatitude': self.ui.maxLatSpinBox.value(),
            'MinimumLongitude': self.ui.minLonSpinBox.value(),
            'MaximumLongitude': self.ui.maxLonSpinBox.value(),
            'Height': self.ui.cellHeightSpinBox.value(),
            'Width': self.ui.cellWidthSpinBox.value()}
        import_mask_dlg = ImportVectorToRasterController(reg_dic)
        import_mask_dlg.exec_()
        # need to assign the result to the mask control
        self.ui.maskLineEdit.setText(
            import_mask_dlg.get_mask_filename())

    def import_region(self):
        '''
        Function to import a region from a region zip.
        '''
        region_file =\
            QFileDialog.getOpenFileName(
                self,
                'Please Select a Region zip to import',
                self.wrksp_setup.get_workspace(),
                'Zip files (*.zip);;All files (*.*)')

        if region_file[0]:
            # Create a temp workspace to unzip to
            region_temp_workspace = os.path.join(self.wrksp_setup.temp_path, os.path.splitext(os.path.basename(region_file[0]))[0] + "_region_temp")
            if os.path.exists(region_temp_workspace):
                shutil.rmtree(region_temp_workspace)
            os.makedirs(region_temp_workspace)

            # Unzip the folder to the temp directory
            with zipfile.ZipFile(region_file[0], 'r') as zip_ref:
                zip_ref.extractall(region_temp_workspace)

            # Read in the config
            config = configparser.ConfigParser()
            config.read(glob.glob(os.path.join(region_temp_workspace, '*_config.ini'))[0])

            # Check if we already have this region defined
            new_reg_name = config.get('Region Definition', 'region_name')
            err = self.__check_new_name__(new_reg_name)
            if err is False:
                reply = QMessageBox.question(
                    self,
                    'New default region?',
                    'Do you want to set this as the default region?',
                    QMessageBox.Yes, QMessageBox.No)

                self.ui.regionComboBox.addItem(new_reg_name)
                self.ui.regionComboBox.setCurrentIndex(
                    self.ui.regionComboBox.count() - 1)

                if reply == QMessageBox.Yes:
                    self.ui.defaultRegComboBox.setCurrentIndex(
                        self.ui.defaultRegComboBox.findText('Yes'))
                else:
                    self.ui.defaultRegComboBox.setCurrentIndex(
                        self.ui.defaultRegComboBox.findText('No'))

                # Copy the unzipped files to their location
                files_to_copy = [
                    'mask_file',
                    'map_file',
                    'map2_file',
                    'sos_file',
                    'wrsi_file',
                    'lgp_file',
                    'whc_file',
                    'sos_color_file']

                for file_to_check in files_to_copy:
                    if config.has_option("Region Definition", file_to_check) and config.get("Region Definition", file_to_check) != "":
                        new_file_path = os.path.join(self.wrksp_setup.get_workspace(), config.get("Region Definition", file_to_check).split("fews_tools_WS" + os.sep)[1])

                        # Create new paths in the config with the current user's file locations
                        config.set("Region Definition", file_to_check, new_file_path)

                        for temp_file_glob in glob.glob(os.path.splitext(os.path.join(region_temp_workspace, os.path.basename(new_file_path)))[0] + ".*"):

                            new_file_path_glob = os.path.join(os.path.dirname(new_file_path), os.path.basename(temp_file_glob))

                            # If the importing file exists, raise a message otherwise copy it over
                            if os.path.exists(new_file_path_glob):
                                iface.messageBar().pushMessage("Warning", f"file: {new_file_path_glob} already exists, not copying when importing {self.ui.regionComboBox.currentText()}", level=Qgis.Warning)
                            else:
                                if not os.path.exists(os.path.dirname(new_file_path_glob)):
                                    os.makedirs(os.path.dirname(new_file_path_glob))
                                shutil.copy(temp_file_glob, new_file_path_glob)

                # Fill the ui
                self.ui.commentLineEdit.setText(config.get('Region Definition', 'comments'))
                self.ui.minLatSpinBox.setValue(float(config.get('Region Definition', 'minimum_latitude')))
                self.ui.maxLatSpinBox.setValue(float(config.get('Region Definition', 'maximum_latitude')))
                self.ui.minLonSpinBox.setValue(float(config.get('Region Definition', 'minimum_longitude')))
                self.ui.maxLonSpinBox.setValue(float(config.get('Region Definition', 'maximum_longitude')))
                self.ui.cellHeightSpinBox.setValue(float(config.get('Region Definition', 'cell_height')))
                self.ui.cellWidthSpinBox.setValue(float(config.get('Region Definition', 'cell_width')))
                self.ui.maskLineEdit.setText(config.get('Region Definition', 'mask_file'))
                self.ui.mapLineEdit.setText(config.get('Region Definition', 'map_file'))
                self.ui.map2LineEdit.setText(config.get('Region Definition', 'map2_file'))
                self.ui.geowrsiCheckBox.setChecked(config.get('Region Definition', 'geowrsi_region') == "True")

                if self.ui.geowrsiCheckBox.isChecked():
                    if config.get('Region Definition', 'geowrsi_periodicity') == "dekadal":
                        self.ui.dekadalRadioButton.setChecked(True)
                        self.ui.pentadalRadioButton.setChecked(False)
                    else:
                        self.ui.dekadalRadioButton.setChecked(False)
                        self.ui.pentadalRadioButton.setChecked(True)

                    self.ui.initialPeriodSpinBox.setValue(int(config.get('Region Definition', 'initial_period')))
                    self.ui.finalPeriodSpinBox.setValue(int(config.get('Region Definition', 'final_period')))
                    self.ui.SOSLineEdit.setText(config.get('Region Definition', 'sos_file'))
                    self.ui.WRSILineEdit.setText(config.get('Region Definition', 'wrsi_file'))
                    self.ui.LGPLineEdit.setText(config.get('Region Definition', 'lgp_file'))
                    self.ui.WHCLineEdit.setText(config.get('Region Definition', 'whc_file'))
                    self.ui.SOSColorLineEdit.setText(config.get('Region Definition', 'sos_color_file'))

                self.save_region()

                shutil.rmtree(region_temp_workspace)

    def export_region(self):
        '''
        Function to export region config and associated files to a zip
        '''

        region_export_file = QFileDialog.getSaveFileName(
            None,
            u'Select save location',
            self.wrksp_setup.get_workspace(),
            '*.zip')

        if region_export_file[0]:
            if not os.path.exists(os.path.dirname(region_export_file[0])):
                os.makedirs(os.path.dirname(region_export_file[0]))
            files_to_copy = []

            # Create a temp workspace to copy files to zip and config
            region_temp_workspace = os.path.join(self.wrksp_setup.temp_path, self.ui.regionComboBox.currentText() + "_region_temp")
            if os.path.exists(region_temp_workspace):
                shutil.rmtree(region_temp_workspace)
            os.makedirs(region_temp_workspace)

            # Instantiate config
            config = configparser.ConfigParser()

            config.add_section('Region Definition')
            config.set('Region Definition', 'region_name', self.ui.regionComboBox.currentText())
            config.set('Region Definition', 'comments', self.ui.commentLineEdit.text())
            config.set('Region Definition', 'minimum_latitude', str(self.ui.minLatSpinBox.value()))
            config.set('Region Definition', 'maximum_latitude', str(self.ui.maxLatSpinBox.value()))
            config.set('Region Definition', 'minimum_longitude', str(self.ui.minLonSpinBox.value()))
            config.set('Region Definition', 'maximum_longitude', str(self.ui.maxLonSpinBox.value()))
            config.set('Region Definition', 'cell_height', str(self.ui.cellHeightSpinBox.value()))
            config.set('Region Definition', 'cell_width', str(self.ui.cellWidthSpinBox.value()))
            config.set('Region Definition', 'mask_file', self.ui.maskLineEdit.text())
            config.set('Region Definition', 'map_file', self.ui.mapLineEdit.text())
            config.set('Region Definition', 'map2_file', self.ui.map2LineEdit.text())
            config.set('Region Definition', 'geowrsi_region', str(self.ui.geowrsiCheckBox.isChecked()))

            # GeoWRSI settings
            if self.ui.geowrsiCheckBox.isChecked():
                if self.ui.dekadalRadioButton.isChecked():
                    config.set('Region Definition', 'geowrsi_periodicity', "dekadal")
                else:
                    config.set('Region Definition', 'geowrsi_periodicity', "pentadal")

                config.set('Region Definition', 'initial_period', str(self.ui.initialPeriodSpinBox.value()))
                config.set('Region Definition', 'final_period', str(self.ui.finalPeriodSpinBox.value()))
                config.set('Region Definition', 'sos_file', self.ui.SOSLineEdit.text())
                config.set('Region Definition', 'wrsi_file', self.ui.WRSILineEdit.text())
                config.set('Region Definition', 'lgp_file', self.ui.LGPLineEdit.text())
                config.set('Region Definition', 'whc_file', self.ui.WHCLineEdit.text())
                config.set('Region Definition', 'sos_color_file', self.ui.SOSColorLineEdit.text())

            region_config_file = os.path.join(region_temp_workspace, self.ui.regionComboBox.currentText() + '_config.ini')

            # Write config file
            with open(region_config_file, 'w') as configfile:
                config.write(configfile)

            for file_to_check in [self.ui.maskLineEdit.text(),
                                self.ui.mapLineEdit.text(),
                                self.ui.map2LineEdit.text(),
                                self.ui.SOSLineEdit.text(),
                                self.ui.WRSILineEdit.text(),
                                self.ui.LGPLineEdit.text(),
                                self.ui.WHCLineEdit.text(),
                                self.ui.SOSColorLineEdit.text()]:
                if file_to_check != "":
                    if not self.wrksp_setup.get_workspace() in file_to_check:
                        QMessageBox.information(
                            self, 'Error',
                            'Required files need to be within your FEWS Tools'
                            ' workspace to export regions.',
                            QMessageBox.Ok)
                        shutil.rmtree(region_temp_workspace)
                        return

                    files_to_copy.append(file_to_check)

            # Copy all region files to prepare for zip
            for file_path in files_to_copy:
                # We need to get all supporting files as well
                for file_to_copy_glob in glob.glob(os.path.splitext(file_path)[0] + ".*"):
                    shutil.copy(file_to_copy_glob, os.path.join(region_temp_workspace, os.path.basename(file_to_copy_glob)))

            zip_out_temp_file = os.path.join(region_temp_workspace, self.ui.regionComboBox.currentText() + "_region.zip")

            cwd = os.getcwd()
            os.chdir(region_temp_workspace)

            with zipfile.ZipFile(zip_out_temp_file, 'w') as zip_file:
                for file in files_to_copy:
                    for file_glob in glob.glob(os.path.splitext(file)[0] + ".*"):
                        zip_file.write(os.path.basename(file_glob), compress_type=zipfile.ZIP_DEFLATED)
                zip_file.write(os.path.basename(region_config_file), compress_type=zipfile.ZIP_DEFLATED)
                zip_file.close()

            os.chdir(cwd)

            shutil.copy(zip_out_temp_file, region_export_file[0])

            shutil.rmtree(region_temp_workspace)


    def new_region(self):
        '''
        Function to create a new region from a reset form.
        '''
        new_region_name_dlg = NewNameController('Region')
        new_region_name_dlg.exec_()
        new_reg_name = new_region_name_dlg.get_new_name()

        if new_reg_name:
            err = self.__check_new_name__(new_reg_name)
            if err is False:
                reply = QMessageBox.question(
                    self,
                    'New default region?',
                    'Do you want to set this as the default region?',
                    QMessageBox.Yes, QMessageBox.No)

                self.ui.regionComboBox.addItem(new_reg_name)
                self.ui.regionComboBox.setCurrentIndex(
                    self.ui.regionComboBox.count() - 1)
                if reply == QMessageBox.Yes:
                    self.ui.defaultRegComboBox.setCurrentIndex(
                        self.ui.defaultRegComboBox.findText('Yes'))
                else:
                    self.ui.defaultRegComboBox.setCurrentIndex(
                        self.ui.defaultRegComboBox.findText('No'))
                self.ui.minLatSpinBox.setValue(0.000)
                self.ui.maxLatSpinBox.setValue(0.000)
                self.ui.minLonSpinBox.setValue(0.000)
                self.ui.maxLonSpinBox.setValue(0.000)
                self.ui.cellHeightSpinBox.setValue(0.050)
                self.ui.cellWidthSpinBox.setValue(0.050)
                self.ui.commentLineEdit.clear()
                self.ui.mapLineEdit.clear()
                self.ui.maskLineEdit.clear()
                self.ui.initialPeriodSpinBox.clear()
                self.ui.finalPeriodSpinBox.clear()
                self.ui.SOSLineEdit.setText("")
                self.ui.WRSILineEdit.setText("")
                self.ui.LGPLineEdit.setText("")
                self.ui.WHCLineEdit.setText("")
                self.ui.SOSColorLineEdit.setText("")
                self.ui.geowrsiCheckBox.setChecked(False)

    def new_region_from_copy(self):
        '''
        Create a new region by copying an existing region.
        '''
        new_region_name_dlg = NewNameController('Region')
        new_region_name_dlg.exec_()
        new_reg_name = new_region_name_dlg.get_new_name()
        if new_reg_name:
            err = self.__check_new_name__(new_reg_name)
            if err is False:
                reply = QMessageBox.question(
                    self, 'New default region?',
                    'Do you want to set this as the default region?',
                    QMessageBox.Yes, QMessageBox.No)

                self.ui.regionComboBox.addItem(new_reg_name)
                self.ui.regionComboBox.setCurrentIndex(
                    self.ui.regionComboBox.count() - 1)
                if reply == QMessageBox.Yes:
                    self.ui.defaultRegComboBox.setCurrentIndex(
                        self.ui.defaultRegComboBox.findText('Yes'))
                else:
                    self.ui.defaultRegComboBox.setCurrentIndex(
                        self.ui.defaultRegComboBox.findText('No'))
                self.save_region()

    def save_region(self):
        '''
        Update region database using widget selections.
        '''
        w_err = self.__check_required_widgets__()
        t_err = self.__validate_text_inputs__()
        wrsi_err = self.__check_wrsi__()
        if w_err is False and t_err is False and wrsi_err is False:
            self.set_widget_val_list()
            self.reg_info.write_region_record(self.widget_val_list)
            self.ui.saveButton.setEnabled(False)
        elif not t_err:
            QMessageBox.information(
                self, 'Error - Missing information',
                'Required fields are missing.\n'
                'Recheck form entries and try again or cancel.',
                QMessageBox.Ok)

    def save_enabled(self):
        '''
        Enable the save button. To save unnecessary writes to the
        database, the button should only be enabled if something has changed
        on the form.
        '''
        self.ui.saveButton.setEnabled(True)

    def set_widget_val_list(self):
        '''
        Get the widget values into a list
        '''
        if self.ui.map2LineEdit.text():
            map_widget_string = (self.ui.mapLineEdit.text() + ',' +
                                 self.ui.map2LineEdit.text())
        else:
            map_widget_string = self.ui.mapLineEdit.text()
        self.widget_val_list =\
            [self.ui.regionComboBox.currentText(),
             self.ui.minLatSpinBox.value(),
             self.ui.maxLatSpinBox.value(),
             self.ui.minLonSpinBox.value(),
             self.ui.maxLonSpinBox.value(),
             self.ui.cellHeightSpinBox.value(),
             self.ui.cellWidthSpinBox.value(),
             self.ui.maskLineEdit.text(),
             map_widget_string,
             self.ui.defaultRegComboBox.currentText(),
             self.ui.commentLineEdit.text()]

        if self.ui.geowrsiCheckBox.isChecked():
            self.widget_val_list.extend(
                [self.ui.initialPeriodSpinBox.value(),
                 self.ui.finalPeriodSpinBox.value()])
        # Otherwise it saves '1' in each spinBox
        else:
            self.widget_val_list.extend([None, None])

        if not self.ui.geowrsiCheckBox.isChecked():
            self.widget_val_list.extend([''])
        elif self.ui.dekadalRadioButton.isChecked():
            self.widget_val_list.extend(['Dekadal'])
        else:
            self.widget_val_list.extend(['Pentadal'])

        self.widget_val_list.extend([
            self.ui.SOSLineEdit.text(),
            self.ui.WRSILineEdit.text(),
            self.ui.LGPLineEdit.text(),
            self.ui.WHCLineEdit.text(),
            self.ui.SOSColorLineEdit.text()])

    def update_form_widgets_for_new_region_selection(self):
        '''
        Function to update form widgets when region selection changes.
        '''
        # use the name to set region object data structure vals
        self.reg_info.query_named_region(self.ui.regionComboBox.currentText())
        # get the values for use here
        self.reg_dic = self.reg_info.get_region_dictionary()
        self.ui.map2LineEdit.clear()  # in case it doesn't exist in selected
        self.ui.commentLineEdit.setText(self.reg_dic['Comments'])
        self.ui.minLatSpinBox.setValue(self.reg_dic['MinimumLatitude'])
        self.ui.maxLatSpinBox.setValue(self.reg_dic['MaximumLatitude'])
        self.ui.minLonSpinBox.setValue(self.reg_dic['MinimumLongitude'])
        self.ui.maxLonSpinBox.setValue(self.reg_dic['MaximumLongitude'])
        self.ui.cellHeightSpinBox.setValue(self.reg_dic['Height'])
        self.ui.cellWidthSpinBox.setValue(self.reg_dic['Width'])
        self.ui.maskLineEdit.setText(self.reg_dic['Mask'])
        map_file_tuple = self.reg_dic['Map'].split(',')
        self.ui.mapLineEdit.setText(map_file_tuple[0])
        if len(map_file_tuple) > 1:
            self.ui.map2LineEdit.setText(map_file_tuple[1])
        self.ui.defaultRegComboBox.setCurrentIndex(
            self.ui.defaultRegComboBox.findText(self.reg_dic['DefaultReg']))

        if not self.ui.geowrsiCheckBox.isChecked():
            self.disable_wrsi_settings()

        if not self.__check_wrsi_region_filled__():
            if self.reg_dic['PeriodType'] == "Dekadal":
                self.ui.dekadalRadioButton.setChecked(True)
            else:
                self.ui.pentadalRadioButton.setChecked(True)

            self.ui.initialPeriodSpinBox.setValue(
                self.reg_dic['InitialPeriod'])
            self.ui.finalPeriodSpinBox.setValue(self.reg_dic['FinalPeriod'])
            self.ui.SOSLineEdit.setText(self.reg_dic['SOS'])
            self.ui.WRSILineEdit.setText(self.reg_dic['WRSI'])
            self.ui.LGPLineEdit.setText(self.reg_dic['LGP'])
            self.ui.WHCLineEdit.setText(self.reg_dic['WHC'])
            self.ui.SOSColorLineEdit.setText(self.reg_dic['SOSColor'])
            self.ui.geowrsiCheckBox.setChecked(True)
        else:
            self.ui.dekadalRadioButton.setChecked(True)
            self.ui.initialPeriodSpinBox.clear()
            self.ui.finalPeriodSpinBox.clear()
            self.ui.SOSLineEdit.setText("")
            self.ui.WRSILineEdit.setText("")
            self.ui.LGPLineEdit.setText("")
            self.ui.WHCLineEdit.setText("")
            self.ui.SOSColorLineEdit.setText("")
            self.ui.geowrsiCheckBox.setChecked(False)
        self.ui.saveButton.setEnabled(False)

    def disable_wrsi_settings(self):
        '''
        Disables wrsi settings if the GeoWRSI Region check box is not toggled
        '''
        self.ui.geowrsiGroupBox.hide()

    def geowrsi_toggled(self):
        '''
        Handle geowrsi check box change.
        '''
        if self.ui.geowrsiCheckBox.isChecked():
            self.ui.geowrsiGroupBox.show()
        else:
            self.ui.geowrsiGroupBox.hide()

    def __check_wrsi_region_filled__(self):
        '''
        Check if the provided dictionary has all the wrsi regions with a value
        '''
        err = False
        req_fields = [self.reg_dic['InitialPeriod'],
                      self.reg_dic['FinalPeriod'],
                      self.reg_dic['PeriodType'],
                      self.reg_dic['SOS'],
                      self.reg_dic['WRSI'],
                      self.reg_dic['LGP'],
                      self.reg_dic['WHC'],
                      self.reg_dic['SOSColor']]

        for entry in req_fields:
            if entry in ['', None]:
                err = True
        return err

    def __check_is_wrsi_region__(self):
        '''
        Check if the required wrsi fields are filled
        '''
        wrsi_err = False
        req_line_edits = [self.ui.SOSLineEdit.text(),
                          self.ui.WRSILineEdit.text(),
                          self.ui.LGPLineEdit.text(),
                          self.ui.WHCLineEdit.text(),
                          self.ui.SOSColorLineEdit.text()]
        for entry in req_line_edits:
            if entry == '':
                wrsi_err = True
        return wrsi_err

    def period_changed(self):
        '''
        Change between dekadal and pentadal periods
        '''
        if self.ui.dekadalRadioButton.isChecked():
            self.ui.lblIniPeriod.setText("Initial Dekad of Season (1 - 36)")
            self.ui.lblFinalPeriod.setText("Final Dekad of Season (1 - 36)")
            self.ui.initialPeriodSpinBox.setMaximum(36)
            self.ui.finalPeriodSpinBox.setMaximum(36)

        else:
            self.ui.lblIniPeriod.setText("Initial Pentad of Season (1 - 72)")
            self.ui.lblFinalPeriod.setText("Final Pentad of Season (1 - 72)")
            self.ui.initialPeriodSpinBox.setMaximum(72)
            self.ui.finalPeriodSpinBox.setMaximum(72)
