#!/usr/bin/env python
# These functions are used for reading and applying user-provided
# threshold and size values from a CSV file with the following
# header names: name, threshold, min, max. The names must match
# either the image file names (in single-plane mode) or the folder
# names containing the image stacks (in multi-plane/normal mode).
#
# Written by Allison Hsiang

import numpy as np
import pandas
import os
import sys
from pathlib import Path
import settings
import images


def read_parameters(param_file):
    '''
    Reads in information in user-provided CSV file.
    '''
    params = pandas.read_csv(param_file)
    return params


def get_directories(run, params):
    '''
    Given a directory, will find all subdirectories contained
    in that directory that exist (single-param mode) or that
    match the names given in the provided parameter matrix
    (multi-param mode).
    '''
    subdirs = [d.path for d in os.scandir(run['directory']) if d.is_dir()]

    if run['param_file']:
        names = list(params['name'])
        final_dirs = [d for d in subdirs if Path(d).stem in names]
    else:
        output_dir = run['output'] + os.sep + run['subdirectory']
        final_dirs = [d for d in subdirs if not d == output_dir]

    return final_dirs


def match_parameters(run, file, params):
    '''
    Matches parameters between input file and
    adjusts run parameters accordingly.
    '''
    headers = list(params.columns)

    name = Path(file).stem
    row = params[params['name'].str.contains(name)]

    for header in headers:

        if header == 'threshold':
            threshold_str = str(row[header].values[0])
            threshold = settings.parse_thresholds(threshold_str)
            if run['mode'] == 'final':
                if len(threshold) > 1:
                    sys.exit('Error: for final mode, only give a single threshold value, not a range.')
                else:
                    value = [threshold[0]]
            else:
                value = threshold

        elif header in ['minimum_size','maximum_size','min','max']: # FLOATS
            conversion = {'min':'minimum_size', 'max':'maximum_size'}
            try:
                value = float(row[header].values[0])
                if header in ['min','max']:
                    header = conversion[header]
            except:
                sys.exit('Error: Unparseable value for {0} in parameter file.'.format(header))

        elif header in ['fill_kernel', 'box_thickness', 'scale_bar_length']: # INTS
            try:
                value = int(row[header].values[0])
            except:
                sys.exit('Error: Unparseable value for {0} in parameter file.'.format(header))

        elif header in ['skip_last_plane', 'debug_images', 'transpose_csv']: # BOOLEANS
            input = str(row[header].values[0])
            try:
                if input in ['True', 'true', 't', 'T']:
                    value = True
                if input in ['False', 'false', 'f', 'F']:
                    value = False
            except:
                sys.exit('Error: Unparseable value for {0} in parameter file.'.format(header))

        else: # All other parameters
            value = str(row[header].values[0])

        run[header] = value

    return run


def parse_parameters(runs):
    '''
    Augments runs based on parameter mode (multi- vs. single-).
    '''
    final_runs = []

    if runs[0]['param_file']: # Multi-param mode
        params = read_parameters(runs[0]['param_file'])

        for idx, row in params.iterrows():
            temp_run = match_parameters(runs[0], row['name'], params)

            thresholds = temp_run['threshold']
            for thresh in thresholds:
                run = temp_run.copy()
                run['threshold'] = thresh
                final_runs.append(run)

    else: # Single-param mode
        if runs[0]['single_dir'] == False: # Multi-dir mode
            subdirs = get_directories(runs[0], None)
            for subdir in subdirs:
                name = Path(subdir).stem
                temp_runs = [dict(run, **{'name':name}) for run in runs]
                final_runs = final_runs + temp_runs

        else: # Single-dir mode
            if runs[0]['single_plane'] == True: # Single-plane mode
                image_list = get_image_list(runs[0]['directory'], runs[0])
                for img in image_list:
                    name = Path(img).stem
                    temp_runs = [dict(run, **{'name':name}) for run in runs]
                    final_runs = final_runs + temp_runs

            else: # Multi-plane mode (canonical mode)
                name = runs[0]['subdirectory']
                temp_runs = [dict(run, **{'name':name}) for run in runs]
                final_runs = final_runs + temp_runs

    return final_runs


def get_image_list(directory, run):
    '''
    Given a directory, returns list of images contained.
    '''
    image_list = images.list_files(directory, run['input_ext'])
    return image_list
