cosmo fmri convert xform

function tr_xform = cosmo_fmri_convert_xform(fmt, xform)
    % convert xform code between numeric and string in fmri dataset
    %
    % tr_xform=cosmo_fmri_convert_xform(fmt, xform)
    %
    % Inputs:
    %   fmt              one of:
    %                    - 'nii' (nifti)
    %                    - 'afni' (afni)
    %                    - 'bv' (BrainVoyager)
    %   xform            either
    %                    - a string, in which it must be one of
    %                       'scanner_anat','aligned_anat','talairach',
    %                       'mni_152', 'unknown'
    %                    - a number, in which case it must be the view type for
    %                       nii (sform or qform) or afni (the first element of
    %                       SCENE_TYPE). Any number in bv corresponds with
    %                       'unknown'.
    %
    % Output:
    %   tr_xform         if the input is a string, then the output is the
    %                    corresponding view type (numeric); and vice versa
    %                    if the viewtype cannot be found, the string 'unknown'
    %                    or the corresponding view type is returned
    %
    % Examples
    %     % Number to string:
    %
    %     % - NIFTI
    %     cosmo_fmri_convert_xform('nii',1)
    %     %|| 'scanner_anat'
    %     cosmo_fmri_convert_xform('nii',2)
    %     %|| 'aligned_anat'
    %     cosmo_fmri_convert_xform('nii',3)
    %     %|| 'talairach'
    %     cosmo_fmri_convert_xform('nii',4)
    %     %|| 'mni_152'
    %     % any unknown number returns 'scanner_anat'
    %     cosmo_fmri_convert_xform('nii',0)
    %     %|| 'scanner_anat'
    %     cosmo_fmri_convert_xform('nii',NaN)
    %     %|| 'scanner_anat'
    %
    %     % - AFNI
    %     cosmo_fmri_convert_xform('afni',0)
    %     %|| 'scanner_anat'
    %     cosmo_fmri_convert_xform('afni',1)
    %     %|| 'aligned_anat'
    %     cosmo_fmri_convert_xform('afni',2)
    %     %|| 'talairach'
    %     % any unknown number returns 'scanner_anat'
    %     cosmo_fmri_convert_xform('afni',10)
    %     %|| 'scanner_anat'
    %     cosmo_fmri_convert_xform('afni',NaN)
    %     %|| 'scanner_anat'
    %
    %     % - BV
    %     % any number returns 'talairach'
    %     cosmo_fmri_convert_xform('bv',0)
    %     %|| 'talairach'
    %     cosmo_fmri_convert_xform('bv',NaN)
    %     %|| 'talairach'
    %
    %     % String to number:
    %
    %     % - NIFTI
    %     cosmo_fmri_convert_xform('nii','scanner_anat')
    %     %|| 1
    %     cosmo_fmri_convert_xform('nii','aligned_anat')
    %     %|| 2
    %     cosmo_fmri_convert_xform('nii','talairach')
    %     %|| 3
    %     cosmo_fmri_convert_xform('nii','mni_152')
    %     %|| 4
    %     cosmo_fmri_convert_xform('nii','unknown')
    %     %|| 1
    %
    %     % - AFNI
    %     cosmo_fmri_convert_xform('afni','scanner_anat')
    %     %|| 0
    %     cosmo_fmri_convert_xform('afni','aligned_anat')
    %     %|| 1
    %     cosmo_fmri_convert_xform('afni','talairach')
    %     %|| 2
    %     % treat as talairach
    %     cosmo_fmri_convert_xform('afni','mni_152')
    %     %|| 2
    %     % unknown
    %     cosmo_fmri_convert_xform('afni','unknown')
    %     %|| 0
    %
    %     % - BV
    %     % all are unknown in BV, because BV does not support this
    %     cosmo_fmri_convert_xform('bv','scanner_anat')
    %     %|| 0
    %     cosmo_fmri_convert_xform('bv','aligned_anat')
    %     %|| 0
    %     cosmo_fmri_convert_xform('bv','talairach')
    %     %|| 0
    %     cosmo_fmri_convert_xform('bv','mni_152')
    %     %|| 0
    %     cosmo_fmri_convert_xform('bv','unknown')
    %     %|| 0
    %
    %     % any other input gives an error
    %     cosmo_fmri_convert_xform('unknown','talairach')
    %     %|| error('unsupported format ''unknown''')
    %     cosmo_fmri_convert_xform('unknown',1)
    %     %|| error('unsupported format ''unknown''')
    %
    % #   For CoSMoMVPA's copyright information and license terms,   #
    % #   see the COPYING file distributed with CoSMoMVPA.           #

    [x, y] = get_mapping(fmt);

    if isnumeric(xform)
        % convert numeric to string
        i = find(y == xform, 1, 'first');
        if isempty(i)
            tr_xform = get_default(x, y);
        else
            tr_xform = x{i};
        end

    elseif ischar(xform)
        % convert string to numeric
        i = find(cosmo_match(x, xform), 1, 'first');
        if isempty(i)
            [unused, tr_xform] = get_default(x, y);
        else
            assert(numel(i) == 1);
            tr_xform = y(i);
        end
    else
        error('unsupported input');
    end

function [xd, yd] = get_default(x, y)
    i = find(isnan(y));
    assert(numel(i) == 1);
    xd = x{i};

    msk = cosmo_match(x, xd);
    msk(i) = false;

    j = find(msk);
    assert(numel(j) == 1);
    yd = y(j);

function [x, y] = get_mapping(fmt)
    if ~ischar(fmt)
        error('first argument must be a string');
    end

    % mapping from codes to indices
    switch fmt
        case 'nii'
            codes = {'scanner_anat', 1; ...
                     'aligned_anat', 2; ...
                     'talairach', 3; ...
                     'mni_152', 4; ...
                     'scanner_anat', NaN}; % default

        case 'afni'
            codes = {'scanner_anat', 0; ...
                     'aligned_anat', 1; ... % ACPC
                     'talairach', 2; ...
                     'mni_152', 2; ...
                     'scanner_anat', NaN}; % default

        case 'bv'
            codes = {'talairach', 0; ...
                     'talairach', NaN}; %

        otherwise
            error('unsupported format ''%s''', fmt);
    end

    x = codes(:, 1);
    y = cell2mat(codes(:, 2));