'''
/***************************************************************************
Name	   :  region_model.py
Description:  Region model class for FEWSTools plugin,
              updated from QGIS2
copyright  :  (C) 2019-2023 by FEWS
email      :  minxuansun@contractor.usgs.gov
Modified   :  11/12/2019 cholen - unset_default_flag_on_non_selected_region
              02/20/2020 cholen - Add write from dictionary.
              01/20/2022 cholen - Remove commented out code.
              06/20/2022 jhowton - Added GeoWRSI region options
              06/23/2022 cholen - Add update_region_filepaths
              07/25/2022 cholen - Add migrate_region_table
              08/09/2022 cholen - Add PROGRAM_SETTINGS to paths
              08/30/2022 cholen - Remove DataDirectory attribute
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 copy
import os

from fews_tools import fews_tools_config as config
from fews_tools.utilities import database_utilities as db_util


class RegionModel:
    '''
    Class to hold region information.
    '''

    def __init__(self):
        self.regions_table_name = 'Regions'
        self.reg_dic = None

        self.update_sql = (
            "UPDATE " + self.regions_table_name +
            " SET MinimumLatitude=?,MaximumLatitude=?, "
            "MinimumLongitude=?,MaximumLongitude=?,Height=?,Width=?,"
            "Mask=?,Map=?,DefaultReg=?,Comments=?, InitialPeriod=?, "
            "FinalPeriod=?, PeriodType =?, SOS=?, WRSI=?, LGP=?, WHC=?,"
            "SOSColor=? WHERE RegionName = ?")
        self.insert_sql = (
            "INSERT INTO " + self.regions_table_name +
            " (RegionName,MinimumLatitude,MaximumLatitude,"
            " MinimumLongitude, MaximumLongitude, Height,Width,"
            " Mask,Map,DefaultReg,Comments, InitialPeriod, FinalPeriod,"
            " PeriodType, SOS, WRSI, LGP, WHC, SOSColor)"
            " VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")

        self.static_data_path = None
        self.map_data_path = None

    def delete_region_record(self, reg_name):
        '''
        Deletes selected region
        :param(string) reg_name: Name of region to delete
        '''
        sql = ('DELETE FROM ' + self.regions_table_name +
               ' WHERE RegionName = ?')
        params = (reg_name, )
        db_util.write_db(sql, params)

    def get_all_region_names(self, db_name=None):
        '''
        Extract region names from regions table. Used to fill
        region combo box when loading form.

        :param(string) db_name: Database name (default=None, will use config)
        :return(list) region_list: Region name list
        '''
        if db_name is None:
            db_name = config.DB_FILE
        sql = 'SELECT * FROM ' + self.regions_table_name
        qry_result = db_util.query_db(sql, None, True, db_name)
        region_list = []
        for row in qry_result:
            region_list.append(row[0])
        return region_list

    def get_region_dictionary(self):
        '''
        Return region dictionary
        '''
        return self.reg_dic

    def query_named_region(self, reg_name, db_name=None):
        '''
        Extracts region information from database and loads it into the class
        variables.
        :param(string) reg_name: Name of region of interest.
        :param(string) db_name: Database name (default=None, will use config)
        :return(boolean) err: True if not found, else false
        '''
        if db_name is None:
            db_name = config.DB_FILE
        err = True
        sql = ("SELECT * FROM " + self.regions_table_name +
               " WHERE RegionName=?")
        params = (str(reg_name), )
        qry_result = db_util.query_db(sql, params, False, db_name)
        if qry_result:  # update the dictionary with the returned query
            self.reg_dic = {
                'RegionName': qry_result[0],
                'MinimumLatitude': qry_result[1],
                'MaximumLatitude': qry_result[2],
                'MinimumLongitude': qry_result[3],
                'MaximumLongitude': qry_result[4],
                'Height': qry_result[5],
                'Width': qry_result[6],
                'Mask': qry_result[7],
                'Map': qry_result[8],
                'DefaultReg': qry_result[9],
                'Comments': qry_result[10],
                'InitialPeriod': qry_result[11],
                'FinalPeriod': qry_result[12],
                'PeriodType': qry_result[13],
                'SOS': qry_result[14],
                'WRSI': qry_result[15],
                'LGP': qry_result[16],
                'WHC': qry_result[17],
                'SOSColor': qry_result[18]
                }
            err = False
        return err

    def query_named_region_pre_wrsi(self, reg_name, db_name=None):
        '''
        Extracts region information from database and loads it into the class
        variables.
        :param(string) reg_name: Name of region of interest.
        :param(string) db_name: Database name (default=None, will use config)
        :return(boolean) err: True if not found, else false
        '''
        if db_name is None:
            db_name = config.OLD_DB_FILE
        err = True
        sql = ("SELECT * FROM " + self.regions_table_name +
               " WHERE RegionName=?")
        params = (str(reg_name), )
        qry_result = db_util.query_db(sql, params, False, db_name)
        if qry_result:  # load the dictionary with the returned query
            self.reg_dic = {
                'RegionName': qry_result[0],
                'MinimumLatitude': qry_result[1],
                'MaximumLatitude': qry_result[2],
                'MinimumLongitude': qry_result[3],
                'MaximumLongitude': qry_result[4],
                'Height': qry_result[5],
                'Width': qry_result[6],
                'Mask': qry_result[7],
                'Map': qry_result[8],
                'DefaultReg': qry_result[9],
                'Comments': qry_result[10],
                'InitialPeriod': None,
                'FinalPeriod': None,
                'PeriodType': None,
                'SOS': None,
                'WRSI': None,
                'LGP': None,
                'WHC': None,
                'SOSColor': None}
            err = False
        return err

    def query_default_region_name(self):
        '''
        Extracts default region name and returns it
        If none are marked as default it returns the first region record
        :return(string) ret_val: Default region name
        '''
        sql = ("SELECT * FROM " + self.regions_table_name +
               " WHERE DefaultReg = 'Yes'")
        qry_result = db_util.query_db(sql)
        if qry_result:
            ret_val = qry_result[0]
        else:
            # get the first region in the list
            reg_name_list = self.get_all_region_names()
            ret_val = reg_name_list[0]
        return ret_val

    def unset_default_flag_on_non_selected_regions(
            self, default_reg_name):
        '''
        Update the default region.
        :params(string) default_reg_name: The new default region name.
        '''
        params = (default_reg_name,)
        sql_write =\
            ("UPDATE " + self.regions_table_name +
             " SET DefaultReg = 'No' WHERE RegionName != ?")
        db_util.write_db(sql_write, params)

        sql_write =\
            ("UPDATE " + self.regions_table_name +
             " SET DefaultReg = 'Yes' WHERE RegionName = ?")
        db_util.write_db(sql_write, params)

    def write_region_record(self, widget_vals):
        '''
        Writes or updates a row in the regions table.
        :params
            widget_vals(list): The widget values from form in this order.
                 RegionName,MinimumLatitude,MaximumLatitude,
                 MinimumLongitude, MaximumLongitude,Height, Width,
                 Mask,Map, DefaultReg, Comments, InitialPeriod, FinalPeriod,
                 SOS, WRSI, LGP, WHC, SOSColor
        '''
        err = self.query_named_region(widget_vals[0])
        loc_widget_vals = copy.deepcopy(widget_vals)
        if err is False:
            loc_widget_vals.append(loc_widget_vals.pop(0))
            sql_write = self.update_sql
        else:
            sql_write = self.insert_sql
        params = tuple(loc_widget_vals)
        db_util.write_db(sql_write, params)
        # update the default region if necessary
        if widget_vals[-10] == 'Yes':
            self.unset_default_flag_on_non_selected_regions(widget_vals[0])

    def write_region_record_from_dic(self, reg_dic):
        '''
        Writes or updates a row in the regions table using a region dictionary.
        :params
            reg_dic: The 'widget' values need to be this order.
                  RegionName,MinimumLatitude,MaximumLatitude,
                  MinimumLongitude, MaximumLongitude,Height, Width,
                  Mask,Map, DefaultReg,Comments
        '''
        param_list = [
            reg_dic['RegionName'],
            reg_dic['MinimumLatitude'],
            reg_dic['MaximumLatitude'],
            reg_dic['MinimumLongitude'],
            reg_dic['MaximumLongitude'],
            reg_dic['Height'],
            reg_dic['Width'],
            reg_dic['Mask'],
            reg_dic['Map'],
            reg_dic['DefaultReg'],
            reg_dic['Comments'],
            reg_dic['InitialPeriod'],
            reg_dic['FinalPeriod'],
            reg_dic['PeriodType'],
            reg_dic['SOS'],
            reg_dic['WRSI'],
            reg_dic['LGP'],
            reg_dic['WHC'],
            reg_dic['SOSColor']]
        self.write_region_record(param_list)

    def update_region_filepaths(self, new_workspace):
        '''
        Function to update the region table with the workspace value.
        :params(string) workspace: Workspace path
        '''
        # fix the special case of having selected the root
        if new_workspace == os.path.abspath(os.sep):
            new_workspace = 'C:'
        # handle any case where we don't end with the os.sep
        if new_workspace[-1] != os.sep:
            new_workspace += os.sep
        region_list = self.get_all_region_names()
        for entry in region_list:
            self.query_named_region(entry)
            self.reg_dic = self.get_region_dictionary()
            # map can have multiple values
            reg_map_list = self.reg_dic["Map"].split(",")
            temp_str = ""
            for map_l in reg_map_list:
                basename = os.path.basename(map_l)
                temp_str += os.path.join(new_workspace,
                                         config.PROGRAM_SETTINGS,
                                         config.DATA,
                                         config.MAPS, basename + ",")
            self.reg_dic["Map"] = temp_str[0:-1]  # dump last comma
            for key in ['Mask', 'SOS', 'WRSI', 'LGP', 'WHC', 'SOSColor']:
                if self.reg_dic[key]:  # we won't always have values for these
                    split_path = self.reg_dic[key].split(
                        config.PROGRAM_SETTINGS + os.sep, 1)
                    self.reg_dic[key] = os.path.join(new_workspace,
                                                     config.PROGRAM_SETTINGS,
                                                     split_path[1])
            self.write_region_record_from_dic(self.reg_dic)

    def migrate_regions(self, workspace):
        '''
        Migrate the regions rows to the new database

        :param(string) workspace: Workspace path to use in migrated table.
        '''
        # get old db datasets
        old_reg_list = self.get_all_region_names(config.OLD_DB_FILE)
        new_reg_list = self.get_all_region_names(config.DB_FILE)
        for entry in old_reg_list:
            if entry in new_reg_list:  # should be up to date
                continue
            # get old record
            err = self.query_named_region_pre_wrsi(entry, config.OLD_DB_FILE)
            # map and mask files still need path added
            # map can have multiple values
            reg_map_list = self.reg_dic["Map"].split(",")
            temp_str = ""
            for map_l in reg_map_list:
                temp_str += os.path.join(workspace,
                                         config.PROGRAM_SETTINGS,
                                         config.DATA,
                                         config.MAPS, map_l + ",")
            self.reg_dic["Map"] = temp_str[0:-1]  # dump last comma
            self.reg_dic["Mask"] = os.path.join(workspace,
                                                config.PROGRAM_SETTINGS,
                                                config.DATA,
                                                config.STATIC,
                                                self.reg_dic["Mask"])
            self.write_region_record_from_dic(self.reg_dic)
