'''
/***************************************************************************
Name	   :  geoclim_utilities.py
Description:  GeoCLIM Utility Functions for FEWSTools plugin,
              updated from QGIS2
copyright  :  (C) 2019-2023 by FEWS
email      :  minxuansun@contractor.usgs.gov
Created    :  12/11/2019 - cholen
Modified   :  01/08/2020 - cholen - Added extract_* functions and widget
                             fill functions
              02/10/2020 - cholen - Add OSError check for invalid zip file
              02/20/2020 - cholen - Revert change to fill_dataset_combo
              03/24/2020 - cholen - Additions for BASIICS and Climatological
                           analysis
              05/26/2020 - cholen - Fix extract_region_cell_counts.. cleanup
              06/09/2020 - cholen - Change replace_value output to GDT_Int16
              07/13/2020 - cholen - reset_cell_size only removes hdr and bil
              07/14/2020 - cholen - Log on exceptions
              08/14/2020 - cholen - Fix loading non-consecutive cross years
              08/26/2020 - cholen - Move zip and unzip to archive_utilities.py
              09/01/2020 - cholen - Add notify_process_completed
              10/29/2020 - cholen - Years list reverse check
              11/05/2020 - cholen - Redo input file checking functions
              11/10/2020 - msun - remove reset_cell_size function
              11/13/2020 - cholen - Fix bugs in download data date selection
                                    functions
              12/03/2020 - cholen - Handle OSError
              01/13/2021 - cholen - Handle regex problems
              03/08/2021 - cholen - Check mask vs region adjusted
              03/10/2021 - cholen - Fix to split prefix from file basename and
                                    handle index error
              04/12/2021 - cholen - Remove unused arg from calc_np_stat
              01/07/2022 - cholen - SCA cleanup, moved gdal functions to
                                    new file, added/renamed functions
              03/25/2022 - cholen - Add remove_temp_raster
              04/05/2022 - cholen - Add tif support, better line edit check,
                                    and FEWS date format.
              05/26/2022 - jhowton - Add crop support
              07/13/0222 - cholen - Handle FEWS daily date format
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 datetime
import glob
import math
import os
import re
import shutil


from PyQt5.QtWidgets import QMessageBox
from qgis.core import QgsMessageLog, Qgis

from fews_tools import fews_tools_config as config
from fews_tools.utilities import geoclim_qgs_utilities as qgs_util

from fews_tools.models.datasets_model import DatasetsModel
from fews_tools.models.region_model import RegionModel
from fews_tools.models.workspace_setup_model import WorkspaceSetupModel

from fews_tools.models.crops_model import CropsModel

def adjust_year_list_for_cross_year(year_list, per_start, per_end, mid_point):
    '''
    Adjust control for cross years
    params(list) - year_list - Year list
    params(string) - per_start - First file period
    params(string) - per_end - Last file period
    params(int) - mid_point - Middle point of period list
    return(list) - cross_year_list
    '''
    # sometimes this gets hit with an empty list, ie
    # in composites dlg, if list is empty, do nothing
    cross_year_list = []
    if year_list:
        year_list_l = sorted(set(year_list))
        if len(per_start) == 3:
            compare_start = per_start[0:2]
            compare_end = per_end[0:2]
        else:
            compare_start = per_start
            compare_end = per_end
        if compare_start > mid_point:
            first_year = str(int(year_list_l[0]) - 1) + '-' + year_list_l[0]
        else:
            first_year = year_list_l[0] + '-' + str(int(year_list_l[0]) + 1)
        if compare_end > mid_point:
            last_year = year_list_l[-1] + '-' + str(int(year_list_l[-1]) + 1)
        else:
            last_year = str(int(year_list_l[-1]) - 1) + '-' + year_list_l[-1]
        cross_year_list = []
        for entry in year_list_l:
            new_year_string = entry + '-' + str(int(entry) + 1)
            cross_year_list.append(new_year_string)
            # we will miss the beginning of a cross year
            # if the available years are not consecutive
            prev_year = str(int(entry) - 1)
            if prev_year not in year_list_l:
                new_year_string = prev_year + '-' + entry
                cross_year_list.append(new_year_string)
        if first_year not in cross_year_list:
            cross_year_list.append(first_year)
        if last_year not in cross_year_list:
            cross_year_list.append(last_year)
        cross_year_list = sorted(set(cross_year_list))
    return cross_year_list


def build_daily_interval_dic():
    """
    Build daily interval dictionary, ignore Feb 29
    """
    temp_date = datetime.datetime.strptime("20190101", "%Y%m%d")
    int_dic = {}
    while temp_date != datetime.datetime.strptime("20200101", "%Y%m%d"):
        key = temp_date.strftime("%b_%d")
        int_dic[key] =\
            {"PER_YEAR": str(temp_date.timetuple().tm_yday),  # Julian day
             "MON_PER":  temp_date.strftime("%d"),
             "FEWS_FMT": temp_date.strftime(".%m.%d") }
        temp_date = temp_date + datetime.timedelta(days=1)

    return int_dic


def build_needed_basenames_list(ds_dic, year_list, period_list):
    '''
    Builds the file basename string, used to search for needed
    files, periods are in file name format already
    param(dic) - ds_dic - Dataset dictionary
    param(list) - year_list - Years
    param(list) - period_list - Periods

    return(list) - needed_files_list_l
    '''
    needed_files_list_l = []
    for entry in period_list:
        for yr_l in year_list:
            needed = (ds_dic['DATAPREFIX'] + yr_l + entry +
                      ds_dic['DATASUFFIX'])
            needed_files_list_l.append(needed)
    return needed_files_list_l


def check_consecutive_process_inputs(ds_dic, start_year, end_year,
                                     start_period, end_period):
    '''
    Checks inputs needed for process for consecutive files.
    This is never j2j
    not passed.
    param(dic) - ds_dic - Dataset dictionary
    param(int) - start_year - Start year
    param(int) - end_year - End year
    param(string) - start_period - Start period like '13' or '051' or '05.1'
    param(string) - end_period - End period like '13' or '051' or '05.1'

    return(list) - needed_basenames_list
    return(list) - available_files
    return(list) - missing_files
    '''
    available_files = []
    missing_files = []
    needed_basenames_list = []
    all_periods_list = get_consecutive_periods_list(ds_dic)

    year_list = [str(item) for item in [
        *range(int(start_year), int(end_year) + 1)]]
    try:
        idx_start = all_periods_list.index(start_period)
        idx_end = all_periods_list.index(end_period)
    except ValueError:
        QgsMessageLog.logMessage(
            'Bad period selected', level=Qgis.Critical)
    intvl_dic = get_interval_dic(ds_dic['PERIODICITY'])
    end_yr_per = len(intvl_dic)
    data_file_list = get_input_file_list(ds_dic)
    # if only one year, then all periods are within it
    if start_year == end_year:
        period_list = all_periods_list[idx_start: (idx_end + 1)]
        needed_basenames_list = build_needed_basenames_list(
            ds_dic, year_list, period_list)
    else:
        # if more than one year, get first period to end of year
        per_list_first_year = all_periods_list[idx_start: end_yr_per + 1]
        needed_basenames_list = build_needed_basenames_list(
            ds_dic, [year_list[0]], per_list_first_year)
        # then beginning of last year up to last period
        per_list_last_year = all_periods_list[0: (idx_end + 1)]
        needed_basenames_list += build_needed_basenames_list(
            ds_dic, [year_list[-1]], per_list_last_year)
        # then any in-between years
        if len(year_list) > 2:
            needed_basenames_list += build_needed_basenames_list(
                ds_dic, year_list[1:-1], all_periods_list)

    for entry in needed_basenames_list:
        temp = os.path.join(ds_dic['DATAFOLDER'], entry)
        if temp in data_file_list:
            available_files.append(temp)
        else:
            missing_files.append(temp)

    needed_basenames_list = sorted(set(needed_basenames_list))
    available_files = sorted(set(available_files))
    missing_files = sorted(set(missing_files))
    return needed_basenames_list, available_files, missing_files


def check_line_edit(control, min_chars=0, max_chars=256):
    '''
    Check contents of line edit control
    params(string) - control - Control name
    params(int) - min_chars - Minimum characters(may be empty if 0)
    params(int) - max_chars - Maximum characters
    return(boolean) - err - True if invalid char else False
    '''
    err = False
    txt = control.text()
    if min_chars != 0 and txt is None:
        err = True
    elif max_chars < len(txt):
        err = True
    else:
        for character in txt:
            if (not character.isalpha() and not character.isdigit() and
                    character not in ['_', '-', '.']):
                err = True
                break
    return err


def check_non_consecutive_process_inputs(ds_dic, year_list,
                                         period_list, j2j=False):
    '''
    Checks inputs needed for process when inputs are not consecutive.
    param(dic) - ds_dic - Dataset dictionary
    param(list) - year_list - Years, may or may not be consecutive, can be like
                     ['2020',...] or like ['2019-2020', ...]
    param(list) - period_list - Periods, may or may not be consecutive
    param(boolean) - j2j  - July to June flag

    return(list) - needed_basenames_list
    return(list) - available_files
    return(list) - missing_files
    '''
    available_files = []
    missing_files = []
    needed_basenames_list = []
    per_list_first_half_year = []
    per_list_second_half_year = []
    mid_point = get_midpoint(ds_dic)
    data_file_list = get_input_file_list(ds_dic)

    if not j2j:  # ['2000', '2001', '2006', '2007']
        for yr_entry in year_list:
            needed_basenames_list += build_needed_basenames_list(
                ds_dic, [yr_entry], period_list)
    else:
        for entry in period_list:
            if entry >= mid_point:  # this is a string comparison
                per_list_second_half_year.append(entry)
            else:
                per_list_first_half_year.append(entry)
        for multi_year_entry in year_list:
            for per_entry in per_list_second_half_year:
                needed_basenames_list += build_needed_basenames_list(
                    ds_dic, [multi_year_entry[:4]], [per_entry])
            for per_entry in per_list_first_half_year:
                needed_basenames_list += build_needed_basenames_list(
                    ds_dic, [multi_year_entry[5:]], [per_entry])
    for entry in needed_basenames_list:
        temp = os.path.join(ds_dic['DATAFOLDER'], entry)
        if temp in data_file_list:
            available_files.append(temp)
        else:
            missing_files.append(temp)

    needed_basenames_list = sorted(set(needed_basenames_list))
    available_files = sorted(set(available_files))
    missing_files = sorted(set(missing_files))

    return needed_basenames_list, available_files, missing_files


def extract_data_period(ds_dic, src_file):
    '''
    Extracts the period that the data file covers.  Period may be period of the
    year or period of the month or the fews_fmt period.
    params(dic) - ds_dic - Dataset dictionary
    params(list) src_file - Input file
    returns(string) - Period
    '''
    sep = "."
    reg_exp = config.DATE_FORMATS_DIC[ds_dic['DATADATEFORMAT']]['REG_EXPR']
    test_date = os.path.splitext(
        os.path.basename(src_file))[0].split(ds_dic['DATAPREFIX'])[1]
    # in case there are bad or weird filenames, like -Copy etc
    dt_st_ck = re.findall(reg_exp, test_date)[0]

    if sep in dt_st_ck:
        temp_list = dt_st_ck.split(sep)  # this will be either len 2 or 3
        if len(temp_list) == 3:
            period = temp_list[1] + sep + temp_list[2]
        else:
            period = temp_list[1]
    else:
        yr_dig = ds_dic['DATADATEFORMAT'].count('Y')
        # start by assuming we have period of year (2 digit)
        period = src_file.split(ds_dic['DATAPREFIX'])[1][yr_dig:(yr_dig + 2)]
        # adjust if we have a month and a period of the month
        if 'MM' in ds_dic['DATADATEFORMAT']:
            if ds_dic['DATADATEFORMAT'][-2:] != 'MM':
                # will have a period of the month (1 digit)
                period = src_file.split(
                    ds_dic['DATAPREFIX'])[1][(yr_dig + 2):(yr_dig + 3)]
    return period


def extract_data_years(ds_dic, src_file_list):
    '''
    Extracts the years that the data in the src_file_list covers.
    params(dic) - ds_dic - Dataset dictionary
    params(list) src_file_list - Available input files
    returns(list) - years list
    '''
    year_list = []
    yr_dig = ds_dic['DATADATEFORMAT'].count('Y')
    for entry in src_file_list:
        # extract the year from the basename
        year = os.path.basename(entry).split(ds_dic['DATAPREFIX'])[1][0:yr_dig]
        if year not in year_list:
            year_list.append(year)
    return year_list


def fill_dataset_combo(control):
    '''
    Fill dataset combo box and set default
    params(string) - control - Control name
    '''
    ds_info = DatasetsModel()
    default_ds = ds_info.query_default_dataset_name()
    fill_misc_widget(control, ds_info.get_all_dataset_names())
    if default_ds:
        control.setCurrentIndex(control.findText(default_ds))
    else:
        control.setCurrentIndex(0)


def fill_dataset_combo_by_type(control, data_type):
    """
    Fill dataset combo box by certain data type
    :param control: Instance attribute from UI class
    :param data_type: The data type name located in confing file

    :return: None
    """
    dataset_info = DatasetsModel()
    dataset_dictionaries = dataset_info.filter_by_data_type(data_type)
    default_ds = dataset_info.query_default_dataset_name()
    fill_misc_widget(control, list(dataset_dictionaries.keys()))
    default_ds_location = control.findText(default_ds)
    if default_ds and default_ds_location != -1:
        control.setCurrentIndex(default_ds_location)
    else:
        control.setCurrentIndex(0)


def fill_ds_type_widget(control, ds_dic):
    '''
    Helper to fill in line edit dataset type widgets
    params(QLineEdit) - control - Line Edit control type
    params(dic) - ds_dic - Dataset dictionary
    '''
    control.clear()

    if ds_dic['DATATYPE'] == config.DATA_TYPES[0][1]:
        wid_val = config.DATA_TYPES[0][0]
    elif ds_dic['DATATYPE'] == config.DATA_TYPES[1][1]:
        wid_val = config.DATA_TYPES[1][0]
    elif ds_dic['DATATYPE'] == config.DATA_TYPES[2][1]:
        wid_val = config.DATA_TYPES[2][0]
    elif ds_dic['DATATYPE'] == config.DATA_TYPES[3][1]:
        wid_val = config.DATA_TYPES[3][0]
    else:  # 'PET':
        wid_val = config.DATA_TYPES[4][0]
    control.setText(wid_val)


def fill_interval_widget(control, ds_dic):
    '''
    Helper to fill in line edit interval widgets
    params(QLineEdit) - control - Line Edit control type
    params(dic) - ds_dic - Dataset dictionary
    '''
    # fill dataset type widget
    control.clear()
    wid_val = None
    if ds_dic['PERIODICITY'] in config.PERIODICITY_LIST:
        wid_val = ds_dic['PERIODICITY']
    control.setText(wid_val)


def fill_misc_widget(control, widget_val_list, sort_reverse=False):
    '''
    Helper to fill in misc list or combo widget
    params(string) - control - Control name
    params(list) - widget_val_list - Value list
    '''
    widget_val_list = sorted(set(widget_val_list))
    # update available years widget
    control.clear()
    if not sort_reverse:
        for val in widget_val_list:
            control.addItem(val)
    else:
        for val in widget_val_list[::-1]:
            control.addItem(val)
    try:  # this will only work if control is a combo box
        control.setCurrentIndex(0)
    except BaseException:
        pass


def fill_misc_widget_no_sort(control, widget_val_list):
    '''
    Helper to fill in misc list or combo widget
    params(string) - control - Control name
    params(list) - widget_val_list - Value list
    '''
    # update available years widget
    control.clear()
    for val in widget_val_list:
        control.addItem(val)
    try:  # this will only work if control is a combo box
        control.setCurrentIndex(0)
    except BaseException:
        pass


def fill_period_widget(control, j2j_flag, periodicity):
    '''
    Helper to fill in period list widgets
    params(string) - control - Control name
    params(boolean) - j2j_flag - True for cross year else false
    params(list) - widget_val_list - Value list
    params(string) - periodicity - periodicity
    '''
    # update available period widget
    period_list = get_interval_list(periodicity, j2j_flag)
    control.clear()
    for per in period_list:
        control.addItem(per)


def fill_region_combo_for_dataset_selection(control, ds_file):
    '''
    Fill region combo box only with regions that are within the dataset extents
    Sets default if in list
    params(string) - control - Control name
    params(string) - ds_file - Dataset file
    '''
    try:
        region_info = RegionModel()
        default_reg = region_info.query_default_region_name()
        ds_extent, _, _, _ =\
            qgs_util.extract_raster_file_params(ds_file)

        ds_available_regions_list = []

        for entry in region_info.get_all_region_names():
            err = region_info.query_named_region(entry)
            if err:
                raise IOError('Database read failed')
            temp_reg_dic = region_info.get_region_dictionary()
            reg_extents = qgs_util.get_region_extent(temp_reg_dic)
            test = qgs_util.check_dataset_vs_region_extents(
                None, ds_extent, reg_extents, False)

            if test is True:
                ds_available_regions_list.append(entry)
        ds_available_regions_list.sort()
        fill_misc_widget(control, ds_available_regions_list)

        if default_reg in ds_available_regions_list:
            control.setCurrentIndex(control.findText(default_reg))
        else:
            control.setCurrentIndex(0)
    except BaseException:
        QgsMessageLog.logMessage(
            'Exception - Unspecified error filling region combo',
            level=Qgis.Critical)


def fill_year_widget(control, j2j_flag, years_list,
                     per_start, per_end, mid_point, sort_reverse=True):
    '''
    Helper to fill in year list widgets (list widgets or combo boxes)
    params(string) - control - Control name
    params(boolean) - j2j_flag - True for cross year else false
    params(list) - years_list - Years
    params(string) - per_start - Period start
    params(string) - per_end - Period end
    params(int) - mid_point - Middle point of period list
    params(boolean) - sort_reverse - True means reverse the sort
    return(list) - widget_value_list - Value_list
    '''
    years_list_l = sorted(set(years_list))

    # update available years widget
    control.clear()
    if j2j_flag:
        widget_value_list = adjust_year_list_for_cross_year(

            years_list_l, per_start, per_end, mid_point)
    else:
        widget_value_list = years_list_l

    if sort_reverse:
        widget_value_list.reverse()

    for year in widget_value_list:
        control.addItem(year)
    try:
        control.setCurrentIndex(0)  # only works for combo boxes
    except BaseException:
        pass
    return widget_value_list


def find_missing_files(ds_dic, input_file_list, max_per,
                       beg_year, beg_mon, beg_per,
                       end_year, end_mon, end_per):
    '''
    Find any files missing between earliest and latest files in dataset.
    param(dic) ds_dic - Dataset dictionary
    param(list) - Input file list
    params(int) - max per - Max periods per year
    param(int) beg_year - The first year
    param(int) beg_mon - The first month
    param(int) beg_per - The first period
    param(int) end_year - The end year
    param(int) end_mon - The end month
    param(int) end_per - The end period

    return(list) - missing_file_list
    '''
    if "." in ds_dic["DATADATEFORMAT"]:
        sep_l = "."
    else:
        sep_l = ""
    dates_list = []
    min_per = 1
    max_per_l = max_per
    min_month = 1
    max_month = 12
    # handle cases where we have only intervals
    if beg_mon is None:  # handle cases where we have periods/yr
        min_month = None
        max_month = None
    else:  # handle cases where we want periods/month
        if ds_dic['PERIODICITY'] == config.PERIODICITY_LIST[0]:
            max_per_l = 3
        elif ds_dic['PERIODICITY'] == config.PERIODICITY_LIST[2]:
            max_per_l = 6
        elif ds_dic['PERIODICITY'] == config.PERIODICITY_LIST[1]:
            min_per = None
            max_per_l = None
        else:
            max_per_l = None

    if beg_year == end_year:
        dates_list = get_file_date_for_year_list(
            beg_year, beg_mon, beg_per, end_mon, end_per, max_per_l, sep_l)
    else:
        # get first year
        dates_list_beg = get_file_date_for_year_list(
            beg_year, beg_mon, beg_per, max_month, max_per_l, max_per_l, sep_l)
        # get last year
        dates_list_end = get_file_date_for_year_list(
            end_year, min_month, min_per, end_mon, end_per, max_per_l, sep_l)
        # if needed get any other years
        dates_list_mid = []
        if end_year - beg_year > 1:
            for yr_l in range(beg_year + 1, end_year):
                dates_list_mid +=\
                    get_file_date_for_year_list(
                        yr_l, min_month, min_per,
                        max_month, max_per_l, max_per_l, sep_l)
        dates_list = dates_list_beg + dates_list_mid + dates_list_end

    dates_list = sorted(set(dates_list), key=None, reverse=False)
    missing_file_list = []

    for entry in dates_list:
        test_string = (ds_dic['DATAPREFIX'] + entry + ds_dic['DATASUFFIX'])
        found = False
        for entry2 in input_file_list:
            if test_string == os.path.basename(entry2):
                found = True
                continue

        if not found:
            missing_file_list.append(test_string)
    return missing_file_list


def find_missing_files_daily(ds_dic, input_file_list,
                    beg_year, beg_mon, beg_day,
                    end_year, end_mon, end_day):
    '''
    Find any files missing between earliest and latest files in daily dataset.
    using the FEWS daily date format "YYYY.MM.DD"
    param(dic) ds_dic - Dataset dictionary
    param(list) - Input file list
    param(int) beg_year - The first year
    param(int) beg_mon - The first month
    param(int) beg_day - The first day
    param(int) end_year - The end year
    param(int) end_mon - The end month
    param(int) end_day - The end day

    return(list) - missing_file_list
    '''
    beg_date_str = str(beg_year) + str(beg_mon).zfill(2) + str(beg_day).zfill(2)
    end_date_str = str(end_year) + str(end_mon).zfill(2) + str(end_day).zfill(2)
    temp_date = datetime.datetime.strptime(beg_date_str, "%Y%m%d")
    dates_list = []
    while temp_date != datetime.datetime.strptime(end_date_str, "%Y%m%d"):
        dates_list.append(temp_date.strftime("%Y.%m.%d"))
        temp_date = temp_date + datetime.timedelta(days=1)

    dates_list = sorted(set(dates_list), key=None, reverse=False)
    missing_file_list = []

    for entry in dates_list:
        test_string = (ds_dic['DATAPREFIX'] + entry + ds_dic['DATASUFFIX'])
        found = False
        for entry2 in input_file_list:
            if test_string == os.path.basename(entry2):
                found = True
                continue

        if not found:
            missing_file_list.append(test_string)
    return missing_file_list


def get_file_date_for_year_list(year, beg_mon, beg_interval,
                                end_mon, end_interval, max_per, sep):
    '''
    Returns a date list for determining missing files.
    param(int) - year
    param(int) - beg_mon - Starting month, may be None
    param(int) - beg_interval - Starting interval, may be None
    param(int) - end_mon - Ending month, may be None
    param(int) - end_interval - Ending interval, may be None
    param(int) - max_per - Can be max periods/year if months are not given,
                           else max periods/month
    returns(list) - List of the date strings included between start and end
    '''
    dates_list_l = []
    if beg_interval is not None:
        interval = beg_interval
    else:  # we have a monthly with no pent or dek
        interval = 1
    if end_interval is not None:
        e_interval = end_interval
    else:  # we have a monthly with no pent or dek
        e_interval = 1

    if beg_mon is not None:
        # handle cases where we have both months and intervals
        if beg_interval is not None:
            for mon in range(beg_mon, (end_mon + 1)):
                if interval > max_per:
                    interval = 1
                while interval <= max_per:
                    dates_list_l.append(str(year) + sep +
                                        str(mon).zfill(2) + sep +
                                        str(interval))
                    interval += 1
                    if (mon == end_mon) and (interval > e_interval):
                        break
        else:  # handle cases where we have only months
            for mon in range(beg_mon, (end_mon + 1)):
                dates_list_l.append(str(year) + sep + str(mon).zfill(2))
    else:  # handle cases where we have only intervals
        for itvl in range(beg_interval, (end_interval + 1)):
            dates_list_l.append(str(year) + sep + str(itvl).zfill(2))
    return dates_list_l


def get_consecutive_periods_list(ds_dic):
    '''
    Used for checking inputs
    '''
    cons_period_list = []
    per_of_month_formats = ['YYYYMMK', 'YYMMK',
                            'YYYYMMP', 'YYMMP']
    intvl_dic = get_interval_dic(ds_dic['PERIODICITY'])
    date_format = ds_dic['DATADATEFORMAT']
    if "." in ds_dic['DATADATEFORMAT']:
        selected_key = 'FEWS_FMT'
    elif date_format in per_of_month_formats:
        selected_key = 'MON_PER'
    else:
        selected_key = 'PER_YEAR'
    for val in intvl_dic.values():
        cons_period_list.append(val[selected_key])

    return sorted(set(cons_period_list))


def get_input_file_list(ds_dic, avg_flag=False):
    '''
    Gets a list of input files for the dataset.
    If avg_flag is false:
        This list will contain only files with filename format:
            (data prefix + data date format + data suffix).
    If avg_flag is true it will contain only files with filename format:
        (avg data prefix + avg data date format + avg data suffix).
    param(dictionary): ds_dic - Dataset info
    returns(list(string)): file_list - Dataset data files( not averages, etc).
    '''
    file_list = []
    temp_file_list = []
    wrksp_setup = WorkspaceSetupModel()
    if avg_flag:
        folder = wrksp_setup.fix_os_sep_in_path(ds_dic['AVGDATAFOLDER'])
        prefix = ds_dic['AVGDATAPREFIX']
        suffix = ds_dic['AVGDATASUFFIX']
        reg_exp = config.AVG_DATE_FORMATS_DIC[
            ds_dic['AVGDATADATEFORMAT']]['REG_EXPR']
    else:
        folder = wrksp_setup.fix_os_sep_in_path(ds_dic['DATAFOLDER'])
        prefix = ds_dic['DATAPREFIX']
        suffix = ds_dic['DATASUFFIX']
        reg_exp = config.DATE_FORMATS_DIC[ds_dic['DATADATEFORMAT']]['REG_EXPR']

    if folder != '':
        temp_file_list = glob.glob(folder + os.sep + prefix + '*' + suffix)
    for entry in temp_file_list:
        # have to split down to what we think is the date string
        # and then check if it matches the expected length of the date string
        # because prefix and/or file path could contain digits that would
        # return an incorrect value if we just use the regex alone
        try:
            test_date = os.path.splitext(
                os.path.basename(entry))[0].split(prefix)[1]
            # in case there are bad or weird filenames, like -Copy etc
            dt_st_ck = re.findall(reg_exp, test_date)[0]
            if dt_st_ck == test_date:
                file_list.append(entry)
        except IndexError:  # will occur if findall comes back empty
            continue
    return file_list


def get_interval_dic(periodicity):
    '''
    Gets the correct interval dictionary based on periodicity.
    params(string): periodicity - Periodicity
    Returns: interval_dic(dic) - Inteval dictionary
    '''
    if periodicity == config.PERIODICITY_LIST[3]:
        interval_dic = build_daily_interval_dic()
    elif periodicity == config.PERIODICITY_LIST[1]:
        interval_dic = config.MONTH_2_NUM_DIC
    elif periodicity == config.PERIODICITY_LIST[0]:
        interval_dic = config.DEKAD_2_NUM_DIC
    else:  # if interval == config.PERIODICITY_LIST[2]:
        interval_dic = config.PENTAD_2_NUM_DIC
    return interval_dic


def get_interval_list(periodicity, jul_2_jun_cross_year=False):
    '''
    Gets period lists. Will be used to fill in GUI period controls.
    params(dic): periodicity - periodicity
    params(boolen): jul_2_jun_cross_year - Flag to specify a July to June
                    order in control.
    Returns: curr_period_list(list(string)) - List of periods.
    '''
    curr_period_list = []
    interval_dic = get_interval_dic(periodicity)
    # note that the key of the dictionary is what we want to fill in controls
    for k in interval_dic:
        curr_period_list.append(k)

    if jul_2_jun_cross_year:
        mid_index = int(len(curr_period_list) / 2)
        second_half = curr_period_list[mid_index:]
        first_half = curr_period_list[0:mid_index]
        curr_period_list = second_half + first_half
    return curr_period_list


def get_midpoint(ds_dic):
    '''
    Gets the midpoint (used for jul2jun setups)
    params(dic) - ds_dic - Dataset dictionary
    returns(integer) - mid_point - The starting index for July from periodcity
    '''
    # find the "midpoint index" of the correct dictionary
    interval_dic = get_interval_dic(ds_dic['PERIODICITY'])
    # note that this will be the "PER_YEAR" value of the midpoint
    if ds_dic["DATADATEFORMAT"] == "YYYY.MM.DD":
        per_ct_str = str(int(len(interval_dic)/2)).zfill(2)
    else:
        per_ct_str = str(int(len(interval_dic)/2) + 1).zfill(2)
    # find the correct key into that PER_YEAR
    my_key = None
    for k in interval_dic:
        if interval_dic[k]['PER_YEAR'] == per_ct_str:
            my_key = k
            break
    # from that key, get the correct midpoint string
    mid_point_per = get_period_string(ds_dic, my_key)
    return mid_point_per


def get_period_string(ds_dic, interval_key):
    '''
    Gets period, either period of year or month and period.
    params(dic) -  ds_dic - Dataset params from database
    params(string) - interval_key - Key value to find.
    return(string) - period - Period string
    '''
    period = None
    interval_dic = get_interval_dic(ds_dic['PERIODICITY'])
    # start by assuming we have period of year (2 digit)
    period_key = 'PER_YEAR'
    # adjust if we have a fews format
    if "." in ds_dic['DATADATEFORMAT']:
        period_key = 'FEWS_FMT'
    # adjust if we have a month and a period of the month
    elif 'MM' in ds_dic['DATADATEFORMAT'] and\
            ds_dic['DATADATEFORMAT'][-2:] != 'MM':
        period_key = 'MON_PER'
    period = interval_dic[interval_key][period_key]
    return period


def get_key_from_period_value(ds_dic, val):
    '''
    Gets key from period, either period of year or month and period.
    params(dic) - ds_dic - Dataset params from database
    params(string) - val - Value to find.
    return(string) -  ret_val - Dictionary key for value
    '''
    ret_val = None
    interval_dic = get_interval_dic(ds_dic['PERIODICITY'])
    # start by assuming we have period of year
    period_key = 'PER_YEAR'
    # adjust if we have a fews format
    if "." in ds_dic['DATADATEFORMAT']:
        period_key = 'FEWS_FMT'
    # adjust if we have a month and a period of the month
    elif 'MM' in ds_dic['DATADATEFORMAT'] and\
            ds_dic['DATADATEFORMAT'][-2:] != 'MM':
        period_key = 'MON_PER'
    for k in interval_dic:
        if interval_dic[k][period_key] == val:
            ret_val = k
            break
    return ret_val


def notify_process_completed(process_name):
    '''
    Notify at end of process
    param(string) - process_name
    returns(boolean) - Flag to close process window or not
    '''
    reply = QMessageBox.question(
        None, 'Process complete',
        (process_name + u' has completed.\nWould you like to close '
         'the window?\nSelect "No" to continue working with ' +
         process_name),
        QMessageBox.Yes, QMessageBox.No)
    if reply == QMessageBox.Yes:
        ret_val = True
    else:
        ret_val = False
    return ret_val


def split_date_string(date_string, date_format_desc):
    '''
    Split the date_string into year, month and period.
    Args:
        date_string(string) - The date.
    Returns:
        year(string) - The year.
        mon(string) - The month.
        per(string) - The period.
    '''
    year = ''
    mon = ''
    per = ''
    if len(date_format_desc) == 1 and len(date_string) <= 2:
        per = date_string
    elif len(date_format_desc) == 2 and len(date_string) == 2:
        per = date_string
    else:
        year_indices = [pos for pos, char in enumerate(
            date_format_desc) if char == 'Y']
        mon_indices = [pos for pos, char in enumerate(
            date_format_desc) if char == 'M']
        for idx in year_indices:
            year += date_string[idx]
        for idx in mon_indices:
            mon += date_string[idx]

        if "K" in date_format_desc:
            dek_indices = [pos for pos, char in enumerate(
                date_format_desc) if char in ['K', 'E']]
            for idx in dek_indices:
                per += date_string[idx]
        elif "P" in date_format_desc:
            pent_indices = [pos for pos, char in enumerate(
                date_format_desc) if char in ['P', 'T']]
            for idx in pent_indices:
                per += date_string[idx]
        elif "D" in date_format_desc:
            day_indices = [pos for pos, char in enumerate(
                date_format_desc) if char =='D']
            for idx in day_indices:
                per += date_string[idx]
        elif "J" in date_format_desc:
            day_indices = [pos for pos, char in enumerate(
                date_format_desc) if char =='J']
            per = date_string[(day_indices[0]):]
    return year, mon, per


def get_input_info_for_cross_year_seasonals(ds_dic, beg_year, period_list):
    '''
    Gathers input files, begin period and end period for seasonal files in
    a cross year setup.
    params(dic) - ds_dic - Dataset dictionary
    params(string) - beg_year - Beginning year
    params(list) - period_list - Periods in the season(consecutive)
    return(list) - seasonal_file_list
    return(string) - beg_per - Beginning period of beginning year
    returns(string) -  end_per - Ending period of second year
    '''
    seasonal_file_list = []
    beg_periods = []
    end_periods = []
    beg_period = None
    end_period = None
    end_year = str(int(beg_year) + 1)
    # split up the periods
    period_midpoint = get_midpoint(ds_dic)

    for entry in period_list:
        if entry > period_midpoint:  # note string comparison
            beg_periods.append(entry)
        else:
            end_periods.append(entry)

    if beg_periods:
        beg_period = sorted(beg_periods)[0]
        for entry in beg_periods:
            temp_filename = (ds_dic['DATAPREFIX'] + beg_year + entry +
                             ds_dic['DATASUFFIX'])
            temp_path = os.path.join(ds_dic['DATAFOLDER'], temp_filename)
            seasonal_file_list.append(temp_path)
    if end_periods:
        end_period = sorted(end_periods)[-1]
        for entry in end_periods:
            temp_filename = (ds_dic['DATAPREFIX'] + end_year + entry +
                             ds_dic['DATASUFFIX'])
            temp_path = os.path.join(ds_dic['DATAFOLDER'], temp_filename)
            seasonal_file_list.append(temp_path)
        if not beg_period:
            beg_period = end_periods[0]
    if not end_period and beg_periods:
        end_period = beg_periods[-1]
    beg_per = get_key_from_period_value(ds_dic, beg_period)
    end_per = get_key_from_period_value(ds_dic, end_period)
    return seasonal_file_list, beg_per, end_per


def get_input_info_for_seasonals(ds_dic, year, period_list):
    '''
    Gathers input files, begin period and end period for seasonal files.

    params(dic) - ds_dic - Dataset dictionary
    params(string) - year - Year
    params(list) - period_list - Periods in the season(consecutive)
    return(list) - seasonal_file_list
    return(string) - beg_per - Beginning period
    return(string) -  end_per - Ending period
    '''
    seasonal_file_list = []
    beg_per = get_key_from_period_value(ds_dic, sorted(period_list)[0])
    end_per = get_key_from_period_value(ds_dic, sorted(period_list)[-1])
    for entry in period_list:
        temp_filename = (ds_dic['DATAPREFIX'] + year + entry +
                         ds_dic['DATASUFFIX'])
        temp_path = os.path.join(ds_dic['DATAFOLDER'], temp_filename)
        seasonal_file_list.append(temp_path)
    return seasonal_file_list, beg_per, end_per


def get_seasonal_file_names(
        ds_dic, reg_str, year_list, per_list, dst_path):
    """
    Get seasonal sum or average filenames.
    Arguments:
    ds_dic -- Dataset info
    reg_str -- Region name with no spaces, can be empty
    year_list -- List of years
    per_list -- [Mar_Pentad1,...., May_Pentad5](order correctly for j2j or not)
    dst_path -- Outputs path
    Returns:
    seasonal_file_list -- List of seasonal files.
    """
    seasonal_file_list = []
    season_type = "sum"
    # in most cases the seasonal sum filename does not use the region name but
    # there are exceptions, so separate with underscore if it's there
    if reg_str:
        reg_str += "_"
    # temperature datases use seasonal avg instead of sum
    if ds_dic["DATATYPE"].upper() in ["TAV", "TMN", "TMX"]:
        season_type = "avg"
    for year in year_list:
        prefix = (reg_str + ds_dic["DATATYPE"].lower() + season_type +
                  str(year) + per_list[0])
        if len(per_list) > 1:
            prefix += ("_to_" + per_list[-1])
        out_string = prefix + ds_dic["DATASUFFIX"]
        output_filename = os.path.join(dst_path, out_string)
        seasonal_file_list.append(output_filename)
    return seasonal_file_list


def convert_gui_periods_to_file_periods(control, ds_dic, sort: bool = True):
    '''
    Translate the selected periods from the GUI text to numeric.
    Example: GUI = OctPent6  List element = either 106 or 60
    params(string) - control - Control name
    params(dic) - ds_dic - Dataset dictionary
    param(bool) - sort - A flag indicated sort the return value
    return(list) - selected_file_periods - Selected periods
    '''
    selected_file_periods = []
    sel_gui_periods = []
    for entry in control.selectedItems():
        sel_gui_periods.append(entry.text())
    for item in sel_gui_periods:
        temp_str =\
            get_period_string(ds_dic, item)
        selected_file_periods.append(temp_str)
    if sort:
        selected_file_periods =\
            sorted(set(selected_file_periods), key=None, reverse=False)
    return selected_file_periods


def get_date_string_list_per_month_format(start_date, end_date,
                                          max_period_per_month):
    '''
    Gets a list of consecutive date strings for a year, month and period
    of month date format, inclusively between a given start and end date.
    params(string) -  start_date
    params(string) -  end_date
    params(int) - max_period_per_month
    returns(list) - date_string_list
    '''
    next_period = start_date
    date_string_list = [next_period]
    while next_period < end_date:
        if max_period_per_month == 31:  # handle daily fews format
            datetime1 = datetime.datetime.strptime(next_period, "%Y.%m.%d")
            next_period = (datetime1 + datetime.timedelta(days=1)).strftime("%Y.%m.%d")
        elif max_period_per_month > 1:
            next_period = get_next_period_of_month(
                next_period, max_period_per_month)
        else:
            next_period = get_next_month(next_period)

        date_string_list.append(next_period)
    return date_string_list


def get_date_string_list_per_year_format(start_date, end_date,
                                         max_period_per_year):
    '''
    Gets a list of consecutive date strings for a year and period of year
    date format, inclusively between a given start and end date.
    params(string) -  start_date
    params(string) -  end_date
    params(int) - max_period_per_year
    returns(list) - date_string_list
    '''
    next_period = start_date
    date_string_list = [next_period]
    while next_period < end_date:  # string comparision
        next_period = get_next_period_of_year(
            int(next_period[:4]), int(next_period[4:]), max_period_per_year)
        date_string_list.append(next_period)

    return date_string_list


def weighted_least_squares_simple_linear_dic(station_dic, key_x, key_y,
                                             key_w=None, missing_val=-9999):
    '''
    Weighted Least squares Simple Linear Function using a dictionary and keys
    possed in to get x, y and w vlaues. For non-weighted version, w_key = None
    param(dic) - station_dic - Dic of station info
    parmas(string) - key_x - Key for x list vals
    parmas(string) - key_y - Key for y list vals
    parmas(string) - key_w - Key for z list vals, None for non-weighted
    params(int) - missing_val - Value that indicates missing data.
    returns(dic) - w_lss_linear_dic(dictionary) - Dictionary of stats results.
    '''
    x_list = [value[key_x] for key, value in station_dic.items()]
    y_list = [value[key_y] for key, value in station_dic.items()]
    if key_w:
        w_list = [value[key_w] for key, value in station_dic.items()]
    else:
        w_list = None
    w_lss_linear_dic = weighted_least_squares_simple_linear_list(
        x_list, y_list, w_list, missing_val)

    return w_lss_linear_dic


def weighted_least_squares_simple_linear_list(
        x_list, y_list, w_list=None, missing_val=-9999):
    '''
    Weighted Least squares Simple Linear Function using lists for x, y
    and w lists arrays. For the non-weighted version, w_list = None
    params(list) - x_list- X axis list, floats
    params(list) - y_list- Y axis list, floats
    params(list) - w_list- Weights list floats. None for non-weighted
    params(int) - missing_val - Value that indicates missing data.
    returns(dic) - w_lss_linear_dic(dictionary) - Dictionary of stats results.
    '''
    x_val = 0.0
    y_val = 0.0
    w_val = 0.0
    sum_y_minus_x = 0.0
    sum_abs_y_minus_x = 0.0
    n_val = 0
    sum_x = 0.0
    sum_y = 0.0
    sum_w = 0.0
    sum_xy = 0.0
    sum_x2 = 0.0
    sum_y2 = 0.0
    mean_x = 0.0
    mean_y = 0.0
    mean_bias = float(missing_val)
    mae = float(missing_val)
    variance_x = float(missing_val)
    variance_y = float(missing_val)
    covariance_xy = float(missing_val)
    slope = float(missing_val)
    intercept = float(missing_val)
    res_squared = float(missing_val)
    residual = float(missing_val)
    std_err_est = float(missing_val)
    std_err_intercept = float(missing_val)
    std_err_slope = float(missing_val)
    for i in x_list:
        temp_index = x_list.index(i)
        if missing_val not in [i, y_list[temp_index]]:
            n_val += 1  # valid observation count
            x_val = float(i)
            y_val = float(y_list[temp_index])
            if w_list is not None:
                w_val = float(w_list[temp_index])
                sum_w = sum_w + w_val
            else:
                w_val = 1.0
            sum_x = sum_x + x_val * w_val
            sum_y = sum_y + y_val * w_val
            sum_y_minus_x += (y_val - x_val)
            sum_abs_y_minus_x += abs(y_val - x_val)

            sum_xy = sum_xy + (x_val * y_val * w_val)
            sum_x2 = sum_x2 + (x_val * x_val * w_val)
            sum_y2 = sum_y2 + (y_val * y_val * w_val)

    if n_val != 0:
        if sum_w != 0:
            ssum_xx = sum_w * sum_x2 - (sum_x * sum_x)
            ssum_xy = sum_w * sum_xy - (sum_x * sum_y)
        else:
            ssum_xx = sum_x2 - (sum_x * sum_x) / n_val
            ssum_xy = sum_xy - (sum_x * sum_y) / n_val
        ssum_yy = sum_y2 - (sum_y * sum_y) / n_val
        mean_x = sum_x / n_val
        mean_y = sum_y / n_val
        mean_bias = sum_y_minus_x / n_val
        mae = sum_abs_y_minus_x / n_val
        variance_x = ssum_xx / n_val
        variance_y = ssum_yy / n_val
        covariance_xy = ssum_xy / n_val
        if ssum_xx != 0:
            slope = ssum_xy / ssum_xx
            if sum_w != 0:
                intercept = (sum_y - (slope * sum_x)) / sum_w
            else:
                intercept = (sum_y - (slope * sum_x)) / n_val

            if ssum_yy != 0 and ssum_xx != 0:
                res_squared = (ssum_xy * ssum_xy) / (ssum_xx * ssum_yy)
                residual = ssum_xy / math.sqrt(ssum_xx * ssum_yy)
            if n_val != 2 and ssum_xx != 0.0 and math.sqrt(ssum_xx) != 0.0:
                temp = (ssum_yy - slope * ssum_xy)
                if temp >= 0:
                    std_err_est = math.sqrt((temp / (n_val - 2)))
                std_err_intercept = std_err_est *\
                    math.sqrt((1 / n_val) + ((mean_x * mean_x) / ssum_xx))
                std_err_slope = std_err_est / math.sqrt(ssum_xx)

    w_lss_linear_dic = {
        'mean_x': mean_x,
        'mean_y': mean_y,
        'variance_x': variance_x,
        'variance_y': variance_y,
        'covariance_xy': covariance_xy,
        'slope': slope,
        'intercept': intercept,
        'res_squared': res_squared,
        'std_err_est': std_err_est,
        'std_err_intercept': std_err_intercept,
        'std_err_slope': std_err_slope,
        'valid_obs_count': n_val,
        'mean_bias': mean_bias,
        'mae': mae,
        'residual': residual}

    return w_lss_linear_dic


def is_files_exist(files_list: list) -> list:
    '''
    Determine if files exist
    Args:
        files_list: A list of absolute path of files

    Returns: A list of absolute path of files that exist

    '''
    exist_file_list = []
    for file_path in files_list:
        if os.path.exists(file_path):
            exist_file_list.append(file_path)
    return exist_file_list


def copy_files(file_list: list, destination: str) -> None:
    '''
    Copy list of files to the destination directory
    Args:
        file_list: A list of absolute path of files that needs to copy
        destination: A absolute path of the destination directory

    Returns: None
    '''
    try:
        for file_path in file_list:
            destination_file = \
                os.path.join(destination, os.path.basename(file_path))
            if os.path.exists(destination_file):
                os.remove(destination_file)
            shutil.copy(file_path, destination)
    except OSError:
        QgsMessageLog.logMessage(
            'Exception - File copy failed',
            level=Qgis.Critical)


def get_dataset_average_file_list(ds_dic):
    '''
    Given dataset dic and needed periods, generate the average
    file list and missing average file list
    :param dataset_info(ds_dic): A dictionary contains the dataset info
    :param dataset_input_file_list(list): list of data files in local
    :return available_average_file_list(list): available average file list
    :return missing_average_file_list(list): missing average file list
    '''
    period_list = get_consecutive_periods_list(ds_dic)
    available_average_file_list = []
    missing_average_file_list = []

    all_avg_file_list = \
        glob.glob(os.path.join(
            ds_dic['AVGDATAFOLDER'],
            ds_dic['AVGDATAPREFIX'] + '*' + ds_dic['AVGDATASUFFIX']))
    for entry in period_list:
        avg_file_name = os.path.join(
            ds_dic['AVGDATAFOLDER'],
            (ds_dic['AVGDATAPREFIX'] + entry +
             ds_dic['AVGDATASUFFIX']))
        if avg_file_name in all_avg_file_list:
            available_average_file_list.append(avg_file_name)
        else:
            missing_average_file_list.append(avg_file_name)
    return sorted(set(available_average_file_list)), sorted(set(missing_average_file_list))


def is_consecutive(year_list: list) -> bool:
    '''
    Function to determine if elements in string list are consecutive
    integers. Used for output filenames.
    Args:
        year_list - The input list, "2011", "2012", etc.
    Returns:
        True if elements are consecutive, otherwise, false.(boolean)
    '''
    # convert to int or the sort doesn't work correctly
    integer_list = []
    for entry in year_list:
        integer_list.append(int(entry))
    # make sure the list is sorted and get rid of any duplicates
    integer_list = sorted(set(integer_list), key=None, reverse=False)

    return sorted(integer_list) == \
        list(range(min(integer_list), max(integer_list)+1))


def get_all_period_string(ds_dic):
    '''
    Given dataset info, return all periods string in a list, based on the
    periodicity of dataset and date data format.

    :param ds_dic: Dataset info
    :return: A list of all periods string
    '''
    interval_dic = get_interval_dic(ds_dic['PERIODICITY'])
    period_list = list(interval_dic.keys())
    period_list = [get_period_string(ds_dic, period) for period in period_list]
    return period_list


def get_next_month(curr_period):
    '''
    Get the next month date string in correct format.
    params(tuple) - curr_period(yyyy, mm)
    returns(string) - next_period
    '''
    sep = "."
    if sep in curr_period:
        temp_tup = curr_period.split(sep)
        year = int(temp_tup[0])
        month = int(temp_tup[1])
    else:
        year = int(curr_period[:4])
        month = int(curr_period[4:])
    next_month = month + 1
    if next_month == 13:
        next_month = 1
    if next_month == 1:
        next_per_year = year + 1
    else:
        next_per_year = year
    if sep in curr_period:
        next_period = (str(next_per_year) + sep + str(next_month).zfill(2))
    else:
        next_period = (str(next_per_year) + str(next_month).zfill(2))
    return next_period

def get_next_period_of_month(curr_period, max_period_of_month):
    '''
    Get the next period for a period of month date format. Only some
    dekadal and pentadal will use this.
    params(tuple) - curr_period(yyyy, mm, pp)
    params(int) - max_period_of_month
    returns(string) - next_period
    '''
    sep = "."
    if sep in curr_period:
        temp_tup = curr_period.split(sep)
        year = int(temp_tup[0])
        month = int(temp_tup[1])
        period_of_month = int(temp_tup[2])
    else:
        year = int(curr_period[:4])
        month = int(curr_period[4:6])
        period_of_month = int(curr_period[6:])

    if period_of_month > max_period_of_month:
        raise IOError
    if month > 12:
        raise IOError
    if period_of_month == max_period_of_month:
        next_month = month + 1
        if next_month == 13:
            next_month = 1
        next_period_of_month = 1
    else:
        next_month = month
        next_period_of_month = period_of_month + 1

    if next_month == 1 and next_period_of_month == 1:
        next_year = year + 1
    else:
        next_year = year
    if sep in curr_period:
        next_period = (str(next_year) + sep +
                       str(next_month).zfill(2) + sep +
                       str(next_period_of_month))
    else:
        next_period = (str(next_year) +
                       str(next_month).zfill(2) +
                       str(next_period_of_month))
    return next_period


def get_next_period_of_year(year, period_of_year, max_period_of_year):
    '''
    Get the next period for a period of year date format.  This is used for
    some monthly and some dekadal and pentadal datasets.
    params(int) - year
    params(int) - period_of_year
    params(int) - max_period_of_year
    returns(string) - next_period
    '''
    if period_of_year > max_period_of_year:
        raise IOError
    if period_of_year == max_period_of_year:
        next_period_of_year = 1
        next_year = year + 1
    else:
        next_period_of_year = period_of_year + 1
        next_year = year

    next_period = str(next_year) + str(next_period_of_year).zfill(2)
    return next_period


def remove_temp_files(src_path):
    '''
    Remove .xlm, .stx and temp folders/files from specified path

    params(string): src_path - The folder to use.
    '''
    try:
        temp_files_list = []
        for entry_a in ["*.xml", "*.stx", "*temp*"]:
            temp_files_list += (glob.glob(os.path.join(src_path, entry_a)))
        for entry in temp_files_list:
            if os.path.isdir(entry):
                shutil.rmtree(entry)
            else:
                os.remove(entry)
    except OSError:
        pass


def remove_raster_file(src_file):
    """
    Remove raster file
    params(string): src_path - The raster to remove.
    """
    try:
        os.remove(src_file)
        if os.path.splitext(src_file)[1] == config.BIL_SUFFIX:
            for entry in [config.HDR_SUFFIX,
                          config.STX_SUFFIX,
                          config.PRJ_SUFFIX,
                          config.BILAUXXML_SUFFIX]:
                os.remove(src_file.replace(config.BIL_SUFFIX, entry))
    except OSError:
        pass


def fill_crop_combo(control):
    '''
    Fill crop combo box and set default
    params(string) - control - Control name
    '''
    crops_info = CropsModel()
    fill_misc_widget(control, crops_info.get_all_crop_names())
    default_crop = crops_info.query_default_crop_name()
    if default_crop:
        control.setCurrentIndex(control.findText(default_crop))
    else:
        control.setCurrentIndex(0)
