def do_backup(input_file):
    counter = 1
    proposed_backup_folder_path = os.path.join(os.path.dirname(os.path.abspath(input_file)), "backups")
    if os.path.isdir(proposed_backup_folder_path) or not os.path.exists(proposed_backup_folder_path):
        backup_folder_path = proposed_backup_folder_path
    else:
        while os.path.isfile(proposed_backup_folder_path + str(counter)):
            counter += 1
        backup_folder_path = proposed_backup_folder_path + str(counter)
    if not os.path.exists(backup_folder_path):
        os.mkdir(backup_folder_path)
    backup_path = os.path.join(backup_folder_path,
                               os.path.basename(input_file) + '.bak' + "-" + str(time.ctime()).replace(":", "-"))
    shutil.copy(input_file, backup_path)
    clear_old_logs.do_clear(os.path.dirname(backup_path), 50)
    return backup_path
def process(database_connection, folders_database, run_log, emails_table, run_log_directory,
            reporting, processed_files, root, args, version, errors_folder, edi_converter_scratch_folder, settings,
            simple_output=None):
    def update_overlay(overlay_text, dispatch_folder_count, folder_total, dispatch_file_count, file_total, footer):
        if not args.automatic:
            doingstuffoverlay.update_overlay(parent=root,
                                             overlay_text=overlay_text + " folder " +
                                                          str(dispatch_folder_count) + " of " +
                                                          str(folder_total) + "," + " file " +
                                                          str(dispatch_file_count) + " of " +
                                                          str(file_total), footer=footer, overlay_height=120)
        elif simple_output is not None:
            simple_output.configure(text=overlay_text + " folder " +
                                         str(dispatch_folder_count) + " of " +
                                         str(folder_total) + "," + " file " +
                                         str(dispatch_file_count) + " of " +
                                         str(file_total))
        root.update()

    def empty_directory(top):
        for folder_root, dirs, files_delete in os.walk(top, topdown=False):
            for name in files_delete:
                os.remove(os.path.join(folder_root, name))
            for name in dirs:
                os.rmdir(os.path.join(folder_root, name))

    global edi_validator_errors
    global global_edi_validator_error_status
    edi_validator_errors = StringIO()
    global_edi_validator_error_status = False

    def validate_file(input_file, file_name):
        global edi_validator_errors
        global global_edi_validator_error_status
        edi_validator_output, edi_validator_error_status, minor_edi_errors = mtc_edi_validator.report_edi_issues(input_file)
        if minor_edi_errors or edi_validator_error_status and reporting['report_edi_errors']:
            edi_validator_errors.write("\r\nErrors for " + file_name + ":\r\n")
            edi_validator_errors.write(edi_validator_output.getvalue())
            edi_validator_output.close()
            global_edi_validator_error_status = True
        return edi_validator_error_status

    error_counter = 0
    processed_counter = 0
    folder_count = 0
    folder_total_count = folders_database.count(folder_is_active="True")
    # loop over all known active folders, in order of alias name
    for parameters_dict in folders_database.find(folder_is_active="True", order_by="alias"):
        global filename
        global send_filename
        folder_count += 1
        file_count = 0
        file_count_total = 0
        update_overlay("processing folder...\n\n", folder_count, folder_total_count, file_count, file_count_total, "")
        if os.path.isdir(parameters_dict['folder_name']) is True:
            print("entering folder " + parameters_dict['folder_name'] + ", aliased as " + parameters_dict['alias'])
            run_log.write(("\r\n\r\nentering folder " + parameters_dict['folder_name'] + ", aliased as " +
                           parameters_dict['alias'] + "\r\n\r\n").encode())
            os.chdir(parameters_dict['folder_name'])
            # strip potentially invalid send_filename characters from alias string
            cleaned_alias_string = re.sub('[^a-zA-Z0-9 ]', '', parameters_dict['alias'])
            # add iso8601 date/time stamp to send_filename, but filter : for - due to send_filename constraints
            folder_error_log_name_constructor = \
                cleaned_alias_string + " errors." + str(time.ctime()).replace(":", "-") + ".txt"
            folder_error_log_name_full_path = os.path.join(errors_folder['errors_folder'],
                                                           os.path.basename(parameters_dict['folder_name']),
                                                           folder_error_log_name_constructor)
            folder_errors_log = StringIO()
            files = [f for f in os.listdir('.')]  # create list of all files in directory
            filtered_files = []
            file_count_total = len(files)
            run_log.write("Checking for new files\r\n".encode())
            print("Checking for new files")
            for f in files:
                file_count += 1
                update_overlay("processing folder... (checking files)\n\n", folder_count, folder_total_count,
                               file_count, file_count_total, "Checking File: " + f)
                if processed_files.find_one(file_name=os.path.join(os.getcwd(), f),
                                            file_checksum=hashlib.md5(open(f, 'rb').read()).hexdigest()) is None or \
                        processed_files.find_one(file_name=os.path.join(os.getcwd(), f), resend_flag=True):
                    filtered_files.append(f)

            file_count = 0
            errors = False
            if len(files) == 0:  # if there are no files in directory, record in log
                run_log.write("No files in directory\r\n\r\n".encode())
                print("No files in directory")
            if len(filtered_files) == 0 and len(files) > 0:
                run_log.write("No new files in directory\r\n\r\n".encode())
                print("No new files in directory")
            if len(filtered_files) != 0:
                run_log.write((str(len(filtered_files)) + " found\r\n\r\n").encode())
                print(str(len(filtered_files)) + " found")
            file_count_total = len(filtered_files)
            for filename in filtered_files:  # iterate over all files in directory
                empty_directory(edi_converter_scratch_folder['edi_converter_scratch_folder'])
                filename = os.path.abspath(filename)
                original_filename = filename
                file_count += 1
                update_overlay("processing folder...\n\n", folder_count, folder_total_count,
                               file_count, file_count_total, "Sending File: " + os.path.basename(original_filename))
                valid_edi_file = True
                if (parameters_dict['process_edi'] == "True"
                        or parameters_dict['tweak_edi']
                        or parameters_dict['split_edi'])\
                        or parameters_dict['force_edi_validation']:
                    if validate_file(filename, original_filename):
                        valid_edi_file = False
                if parameters_dict['split_edi'] and valid_edi_file:
                    run_log.write(("Splitting edi file " + original_filename + "...\r\n").encode())
                    print("Splitting edi file " + original_filename + "...")
                    try:
                        split_edi_list = split_edi.do_split_edi(filename, edi_converter_scratch_folder[
                            'edi_converter_scratch_folder'])
                        if len(split_edi_list) > 1:
                            run_log.write(
                                ("edi file split into " + str(len(split_edi_list)) + " files\r\n\r\n").encode())
                            print("edi file split into " + str(len(split_edi_list)) + " files")
                    except Exception as error:
                        split_edi_list = [filename]
                        record_error.do(run_log, folder_errors_log,
                                        "splitting edi file failed with error: " + str(error), filename, "edi splitter")
                else:
                    split_edi_list = [filename]
                if len(split_edi_list) <= 1 and parameters_dict['split_edi']:
                    run_log.write("Cannot split edi file\r\n\r\n".encode())
                    print("Cannot split edi file")
                    split_edi_list = [filename]
                for send_filename in split_edi_list:
                    if errors is True:
                        break
                    stripped_filename = re.sub('[^A-Za-z0-9. ]+', '', os.path.basename(send_filename))
                    if os.path.exists(send_filename):
                        if valid_edi_file:
                            if parameters_dict['process_edi'] == "True" and errors is False:
                                # if the current file is recognized as a valid edi file,
                                # then allow conversion, otherwise log and carry on
                                if parameters_dict['convert_to_format'] == "csv":
                                    output_filename = os.path.join(
                                        edi_converter_scratch_folder['edi_converter_scratch_folder'],
                                        os.path.basename(stripped_filename) + ".csv")
                                    if os.path.exists(os.path.dirname(output_filename)) is False:
                                        os.mkdir(os.path.dirname(output_filename))
                                    try:
                                        run_log.write(("converting " + send_filename + " from EDI to CSV\r\n").encode())
                                        print("converting " + send_filename + " from EDI to CSV")
                                        convert_to_csv.edi_convert(send_filename, output_filename,
                                                                   parameters_dict['calculate_upc_check_digit'],
                                                                   parameters_dict['include_a_records'],
                                                                   parameters_dict['include_c_records'],
                                                                   parameters_dict['include_headers'],
                                                                   parameters_dict['filter_ampersand'],
                                                                   parameters_dict['pad_a_records'],
                                                                   parameters_dict['a_record_padding'])
                                        run_log.write("Success\r\n\r\n".encode())
                                        send_filename = output_filename
                                    except Exception as error:
                                        print(str(error))
                                        errors = True
                                        record_error.do(run_log, folder_errors_log, str(error), str(send_filename),
                                                        "EDI Processor")

                            if parameters_dict['tweak_edi'] is True:
                                output_filename = os.path.join(edi_converter_scratch_folder['edi_converter_scratch_folder'],
                                                               os.path.basename(stripped_filename))
                                if os.path.exists(os.path.dirname(output_filename)) is False:
                                    os.mkdir(os.path.dirname(output_filename))
                                try:
                                    edi_tweaks.edi_tweak(send_filename, output_filename,
                                                         parameters_dict['pad_a_records'],
                                                         parameters_dict['a_record_padding'])
                                    send_filename = output_filename
                                except Exception as error:
                                    print(str(error))
                                    errors = True
                                    record_error.do(run_log, folder_errors_log, str(error), str(send_filename),
                                                    "EDI Processor")

                        # the following blocks process the files using the specified backend,
                        # and log in the event of any errors
                        if parameters_dict['process_backend_copy'] is True and errors is False:
                            try:
                                print("sending " + str(send_filename) + " to " +
                                      str(parameters_dict['copy_to_directory']) + " with copy backend")
                                run_log.write(("sending " + str(send_filename) + " to " +
                                               str(parameters_dict[
                                                       'copy_to_directory']) + " with copy backend\r\n\r\n").encode())
                                copy_backend.do(parameters_dict, send_filename)
                                run_log.write("Success\r\n\r\n".encode())
                            except Exception as error:
                                print(str(error))
                                record_error.do(run_log, folder_errors_log, str(error), str(send_filename),
                                                "Copy Backend")
                                errors = True
                        if parameters_dict['process_backend_ftp'] is True and errors is False:
                            try:
                                print(
                                    "sending " + str(send_filename) + " to " + str(parameters_dict['ftp_server']) +
                                    str(parameters_dict['ftp_folder']) + " with FTP backend")
                                run_log.write(
                                    ("sending " + str(send_filename) + " to " + str(parameters_dict['ftp_server']) +
                                     str(parameters_dict['ftp_folder']) + " with FTP backend\r\n\r\n").encode())
                                ftp_backend.do(parameters_dict, send_filename)
                                run_log.write("Success\r\n\r\n".encode())
                            except Exception as error:
                                print(str(error))
                                record_error.do(run_log, folder_errors_log, str(error), str(send_filename),
                                                "FTP Backend")
                                errors = True
                        if parameters_dict['process_backend_email'] is True and errors is False and \
                                settings['enable_email']:
                            try:
                                print("sending " + str(send_filename) + " to " + str(parameters_dict['email_to']) +
                                      " with email backend")
                                run_log.write(
                                    ("sending " + str(send_filename) + " to " + str(parameters_dict['email_to']) +
                                     " with email backend\r\n\r\n").encode())
                                email_backend.do(parameters_dict, settings, send_filename)
                                run_log.write("Success\r\n\r\n".encode())
                            except Exception as error:
                                record_error.do(run_log, folder_errors_log, str(error), str(send_filename),
                                                "Email Backend")
                                errors = True
                if errors is False:
                    try:
                        if processed_files.count(file_name=str(original_filename),
                                                 resend_flag=True) > 0:
                            file_old_id = processed_files.find_one(file_name=str(original_filename), resend_flag=True)
                            processed_files_update = dict(resend_flag=False, id=file_old_id['id'])
                            processed_files.update(processed_files_update, ['id'])

                        processed_files.insert(dict(file_name=str(original_filename),
                                                    folder_id=parameters_dict['id'],
                                                    folder_alias=parameters_dict['alias'],
                                                    file_checksum=hashlib.md5(open(original_filename, 'rb').read())
                                                    .hexdigest(),
                                                    sent_date_time=datetime.datetime.now(),
                                                    copy_destination=parameters_dict['copy_to_directory'] if
                                                    parameters_dict['process_backend_copy'] is True else "N/A",
                                                    ftp_destination=parameters_dict['ftp_server'] +
                                                                    parameters_dict['ftp_folder'] if
                                                    parameters_dict['process_backend_ftp'] is True else "N/A",
                                                    email_destination=parameters_dict['email_to'] if
                                                    parameters_dict['process_backend_email'] is True else "N/A",
                                                    resend_flag=False))
                    except Exception as error:
                        record_error.do(run_log, folder_errors_log, str(error), str(original_filename), "Dispatch")
                        errors = True
                if errors is False:
                    processed_counter += 1
                else:
                    break
            if errors is True:
                error_counter += 1
                if os.path.exists(errors_folder['errors_folder']) is False:
                    record_error.do(run_log, folder_errors_log, "Base errors folder not found",
                                    str(parameters_dict['folder_name']), "Dispatch Error Logger")
                    print("Base error folder not found, " + "making one")
                    os.mkdir(errors_folder['errors_folder'])
                if os.path.exists(os.path.dirname(folder_error_log_name_full_path)) is False:
                    record_error.do(run_log, folder_errors_log, "Error folder Not Found",
                                    str(parameters_dict['folder_name']),
                                    "Dispatch Error Logger")
                    print("Error folder not found for " + parameters_dict['folder_name'] + ", " + "making one")
                    try:
                        os.mkdir(os.path.dirname(folder_error_log_name_full_path))
                    except IOError:  # if we can't create error logs folder, put it in run log directory
                        record_error.do(run_log, folder_errors_log, "Error creating errors folder",
                                        str(parameters_dict['folder_name']), "Dispatch Error Logger")
                        folder_error_log_name_full_path = os.path.join(run_log_directory,
                                                                       folder_error_log_name_constructor)
                try:
                    folder_errors_log_write = open(folder_error_log_name_full_path, 'wb')
                    clear_old_logs.do_clear(os.path.dirname(folder_error_log_name_full_path), 500)
                    folder_errors_log_write.write(("Program Version = " + version + "\r\n\r\n").encode())
                    folder_errors_log_write.write(folder_errors_log.getvalue().encode())
                    if reporting['enable_reporting'] == "True":
                        emails_table.insert(dict(log=folder_error_log_name_full_path,
                                                 folder_alias=parameters_dict['alias'],
                                                 folder_id=parameters_dict['id']))
                except Exception as error:
                    # if file can't be created in either directory, put error log inline in the run log
                    print("can't open error log file,\r\n error is " + str(error) + "\r\ndumping to run log")
                    run_log.write(("can't open error log file,\r\n error is " + str(error) +
                                   "\r\ndumping to run log\r\n").encode())
                    run_log.write(("error log name was: " + folder_error_log_name_constructor + "\r\n\r\n").encode())
                    run_log.write(folder_errors_log.getvalue().encode())
                    run_log.write("\r\n\r\nEnd of Error file\r\n\r\n".encode())
            else:
                database_connection.query("DELETE FROM processed_files WHERE ROWID IN (SELECT id FROM processed_files"
                                          " WHERE folder_id=" + str(parameters_dict['id']) +
                                          " ORDER BY id DESC LIMIT -1 OFFSET 5000)")
                processed_files_update = dict(resend_flag=False, folder_id=parameters_dict['id'])
                processed_files.update(processed_files_update, ['folder_id'])
            folder_errors_log.close()
        else:
            # if the folder is missing, complain and increment error counter
            run_log.write(("\r\nerror: " + os.path.abspath(parameters_dict['folder_name']) + " is missing " + " for " +
                           parameters_dict['alias'] + "\r\n\r\n").encode())
            print("error: " + os.path.abspath(parameters_dict['folder_name']) + " is missing " + " for " +
                  parameters_dict['alias'])
            error_counter += 1
    if global_edi_validator_error_status is True:
        validator_log_name_constructor = "Validator Log " + str(time.ctime()).replace(":", "-") + ".txt"
        validator_log_path = os.path.join(run_log_directory, validator_log_name_constructor)
        validator_log_file = open(validator_log_path, 'wb')
        validator_log_file.write(edi_validator_errors.getvalue().encode())
        edi_validator_errors.close()
        validator_log_file.close()
        if reporting['enable_reporting'] == "True":
            emails_table.insert(dict(log=validator_log_path))
    print(str(processed_counter) + " processed, " + str(error_counter) + " errors")
    run_log.write(
        ("\r\n\r\n" + str(processed_counter) + " processed, " + str(error_counter) + " errors" + "\r\n\r\n").encode())
    if error_counter > 0:
        return True
    else:
        return False