# -*- coding: utf-8 -*-
"""
@author: petrm
"""

import os
import sys
import numpy as np

# need to add the project dir with the utilities folder to path: 
project_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
sys.path.append(project_dir)

from utilities.magn_prep.IR_block import IR_block




def create_params_prep_field(params):

    if params['IR']:
        params['inv_prep'] = 'IR'
        
    return params


def magn_prep_calc(params, scanner_parameters, split_dur = False, calc_offsets = True):
    
    params = create_params_prep_field(params)

    prep_calc = ()
    prep_dur = 0
    IR_dur = 0
    contr_prep_dur = 0
    
    # start with IR
    
    IR_calc_list = []

    try:                        # using try because match case for some reason doesn't work
        functions = {                       
        'IR'              : IR_block,           # inv_prep functions listed in the dictionary
        }

        func = functions.get(params['inv_prep'])    # choosing one of them according to params.

        if calc_offsets:
            
            IR_geom_offsets = (np.linspace(0, params['sl_nb']-1, np.int16(params['sl_nb'])) \
                               - 0.5*(np.double(params['sl_nb'])-1)) \
                               * (params['sl_thkn']*(100+params['sl_gap'])/100)
            params['inv_thkn'] = params['sl_thkn']          # selective inversion of the slice
                               
        else:
            
            IR_geom_offsets = [0]
            
            if 'FoV_ss' in params:
                params['inv_thkn'] = params['FoV_ss']    # selective inversion of the whole FoV, e.g. in 3D
            else: 
                print(' ')
                print('!!!      WARNING      !!!')
                print('Check the parameter of the inversion slab thickness!')
                print("Using the default value params['inv_thkn'] = 0.45 m")
                params['inv_thkn'] = 0.45
            
        for IR_geom_offset in IR_geom_offsets:
            IR_calc, IR_dur = func(params, scanner_parameters, IR_geom_offset)
            IR_calc_list.append(IR_calc) # list of the IR objects differing only in freq_offsets
        
        prep_calc = prep_calc + (IR_calc_list,)
        prep_dur += IR_dur
        
    except:
        prep_calc = prep_calc + (None,)   # NoneType in the first postion == no IR
    
    # contr_prep functions:
    
    return prep_calc, prep_dur        # all calculated objects and timings stored here



def magn_prep_add(prep_calc, seq, curr_slice = None, only_one = None):
    # function to add magn_prep objects. 
    # prep_calc contains all objects calculated in magn_prep_calc
    # seq is provided from the main code
    # curr_slice is provided from the main code
    # only_one can be:
        # 'inv_prep' – if you need to add only inversion options at the place 
        # where the function is called
        # 'contr_prep' – if you need only contrast preparations at 
        # the place where the function is called
    
    if prep_calc == (None, None):       
        return seq
    
    # prep_calc is a tuple where all calculated inv_prep and contr_prep stuff is stored. 
    # The first element of this tuple contains the Standard Inversion objects. It is a list.
    # The length of this list is defined by the number of inversion slices (= Ex slices in 2D)
    # If this list has only one element, it means that we have 1 inversion slice 
    #                                           (e.g. a huge inversion slab for 3D)
    #
    # Lets choose one piece of inversion data from this list, corresponding to curr_slice: 
    #                  IR_objects_curr_slice = prep_calc[0][curr_slice]
    #
    # This itself is a tuple. 
    # Each element of this tuple is a list of IR objects that we need to add to 
    # the sequence simultaneously, i.e. inversion pulse and inversion gradient. 
    # These elements (blocks) are added in a loop over IR_objects_curr_slice 
    # one after another.
    
    
    if not (prep_calc[0] is None): # if IR was calculated
    
        if not (curr_slice is None): 
            # function is called from the slice loop. 
            IR_objects_curr_slice = prep_calc[0][curr_slice]
        else:
            # function is called outside the slice loop
            IR_objects_curr_slice = prep_calc[0][0]
    
        for blocks in IR_objects_curr_slice:
            seq.add_block(*blocks) # add the list-stored blocks of IR objects of the current slice

    
    return seq
