function dicomrename(fpathin, fnames, action, stringname, stringformat)
% DICOMRENAME Rename DICOM-files based on the value of fields in the header
%    DICOMRENAME will present the user with a dialog to select either DICOM 
%    files or the Siemens implementation of DICOM IMA. It will rename the 
%    files based on info in the header of the file using a default naming 
%    schema defined in the first few lines of source code of this function. 
%
%    DICOMRENAME(PATH, FILES) will do the same as explained above using the
%    files supplied as an argument to the function. FILES should be a cell 
%    array of filenames. PATH should be a character array. Similar to the 
%    Matlab native function UIGETFILE using the option 'MultiSelect','On' 
%    or when using one of the functions WILDCARDSEARCH or REGEXPDIR.
% 
%    Example:
%     fpath = 'c:\test\';
%     fnames = {'MRPATIENT.MR.FANCY_STUDY.2.11.2009.01.22.17.08.15.9215.IMA', ...
%               'MRPATIENT.MR.FANCY_STUDY.2.12.2009.01.22.17.08.15.9875.IMA'};
%     dicomrename(fpath, fnames);
%    
%    DICOMRENAME(PATH, FILES, ACTION) the extra optional argument ACTION 
%    allows the user to specify the action. Options are 'rename' the file 
%    or create a 'copy' of the file. The default action is 'copy'. The 
%    original file name will not be preserved and cannot be restored unless 
%    it is already stored as a field in the DICOM header. 
%
%    Example:
%     fpath = 'c:\test\';
%     fnames = {'MRPATIENT.MR.FANCY_STUDY.2.11.2009.01.22.921875.13574960.IMA', ...
%               'MRPATIENT.MR.FANCY_STUDY.2.12.2009.01.22.921875.13574960.IMA'};
%     dicomrename(fpath, fnames, 'rename');
%
%    DICOMRENAME(PATH, FILES, ACTION, STRINGNAME) the optional argument
%    STRINGNAME allows the user to specify the naming convention to be used
%    based on available fields in the DICOM header. By default the fields
%    'PatientName.FamilyName','SeriesDescription', 'SeriesNumber' and 
%    'InstanceNumber' are used. These correspond to common fields in the 
%    Siemens MRI DICOM implementation (as current in 2009). Have a look at 
%    the source code of this function on how to use or (permanently) change
%    this option. Use the function DICOMINFO to get a list of the available
%    fields for your DICOM files. 
%
%    DICOMRENAME(PATH, FILES, ACTION, STRINGNAME, STRINGFORMAT) the extra 
%    optional argument STRINGFORMAT allows the user to specify the 'post'- 
%    reading formatting of every field individually. As STRINGNAME, the
%    field STRINGFORMAT is a cell array of strings. The strings are 
%    evaluated at runtime. The simplest method directs the read field 
%    directly to the name part without any further processing. Escape names
%    for the fields are <in> for the value read from the header and <out> 
%    for the string to be included in the filename. See the source code for
%    an eloborate example. 
%
%    For more info on this function and how to use it, bug reports, feature
%    requests, etc. feel free to contact the author.
%
%    See also DICOMINFO, WILDCARDSEARCH, REGEXPDIR

%==========================================================================
% B.C. Hamans (b.c.hamans@rad.umcn.nl) http://www.hamans.com/mri       2009       
%==========================================================================

%==========================================================================
%           UPDATE THE VARIABLES BELOW FOR YOUR DICOM FILES
%==========================================================================

% Separator of field names in the output file name. 
% Examples: .-_~  Not allowed: \/:*?"<>|
separator = '.';

% Array of DICOM header elements to use for file naming
namestring = {'PatientName.FamilyName',...
              'SeriesDescription',...
              'SeriesNumber',...
              'InstanceNumber'}; 
% Default for Siemens IMA: namestring = {'PatientName.FamilyName',...
%                                        'SeriesDescription',...
%                                        'SeriesNumber',...
%                                        'InstanceNumber'};           

% Array of formatting for the elements
formatstring = {'<out>=<in>;',... 
                '<out>=<in>;',... 
                '<out>=num2str(100+<in>);<out>=<out>(2:3);',...
                '<out>=num2str(1000+<in>);<out>=<out>(2:4);'}; 
% Default for Siemens IMA: formatstring = {'<out>=<in>;',... 
%                                          '<out>=<in>;',... 
%                           '<out>=num2str(100+<in>);<out>=<out>(2:3);',...
%                           '<out>=num2str(1000+<in>);<out>=<out>(2:4);'}; 
            
% Examples regarding the 'formatstring' variable or STRINGFORMAT argument
%  '<out>=<in>;' Simplest form
%  '<out>=strcat(''NAME='',<in>);' Prepends the string 'NAME='. Notice the 
%                                  double quotes! 
%  '<out>=strcat(''TE='',num2str(<in>),''ms'');' Prepends the string 'TE=' 
%                                                converts the echo time to 
%                                                a string and appends the 
%                                                string 'ms'. Note that the
%                                                <in> did not have the
%                                                class character.
%  '<out>=num2str(1000+<in>);<out>=<out>(2:4);'}; Prepend zeros to get 
%                                                 001 to 010 etc instead of
%                                                 1 to 10
% Not allowed characters in any string: \/:*?"<>|
            
%==========================================================================
%           DO NOT CHANGE CODE BELOW THIS LINE FOR NORMAL USAGE
%==========================================================================

% Check arguments
if nargin < 5
    stringformat = formatstring;
    if nargin < 4
        stringname = namestring; 
        if nargin < 3
            action = 'copy';
            if nargin == 1
                error(nargchk(2,2, nargin));
            elseif nargin == 0 
                [fnames, fpathin] = uigetfile(...
                    {'*.dcm;*.ima', 'Compatible files (*.dcm; *.ima)';...
                    '*.dcm', 'DICOM Files (*.dcm)';...
                    '*.ima', 'Siemens IMA Files (*.ima)';...
                    '*.*','All files (*.*)';},...
                    'Open', 'MultiSelect', 'on');    
                if isequal(fnames,0)
                    return 
                end
            end
        end
    end
else
    error(nargchk(0,5, nargin));
end

%==========================================================================

% Loop through all files in fnames
if ~iscell(fnames) 
    fnames={fnames};
end
for i=1:length(fnames)
    namestring = stringname;
    [fpath,fname,fext] = fileparts(fullfile(fpathin,cell2mat(fnames(i))));
    disp(strcat('Reading: <a href="', fullfile(fpath,strcat(fname,fext)),...
        '">', fullfile(fpath,strcat(fname,fext)), '</a>'));
    
    % Read dicom header
    dinfo=dicominfo(fullfile(fpath,strcat(fname,fext)));
    
    % Construct the new file name
    newfname = '';
    for j=1:length(namestring)        
        structname = 'dinfo';
        % Handle nested elements e.g. 'PatientName.FamilyName'
        namestr=cell2mat(namestring(j));
        if strfind(namestr, '.')
            while true
                [str, namestr] = strtok(namestr, 'autoNYR1.');
                if isempty(namestr),
                    namestring(j) = {str};
                    break;  
                end
                structname = strcat(structname, '.', str);
            end
        end

        % Read the value of the field and perform the actions as defined in
        % STRINGFORMAT argument or 'formatstring' variable
        eval(cell2mat(strrep(strrep(stringformat(j),'<out>','newpart'),...
            '<in>','getfield(eval(structname),cell2mat(namestring(j)))'))); 
        newfname = strcat(newfname, separator, newpart);
    end
    newfname = newfname(length(separator)+1:length(newfname));
        
    % Copy
    disp(strcat('Writing: <a href="', fullfile(fpath,strcat(newfname,fext)),...
        '">', fullfile(fpath,strcat(newfname,fext)), '</a>'));
    try
        copyfile(fullfile(fpath,strcat(fname,fext)), fullfile(fpath,strcat(newfname,fext))); 
    catch
        error('Failed. Destination not writable? Illegal character in file name?')
    end
    
    % Remove if rename
    if strncmpi(action, 'rename', 4)
        disp(strcat('Removing: <a href="', fullfile(fpath,strcat(fname,fext)),...
            '">', fullfile(fpath,strcat(fname,fext)), '</a>'));
        try
            delete(fullfile(fpath,strcat(fname,fext)));
        catch
            error('Failed. Delete it by hand.');
        end
    end
end

%==========================================================================
% Changelog:
%  27-01-2009 v1.00 (BCH)  Initial release
%  29-01-2009 v1.1  (BCH)  Added functionality to format the name fields
%==========================================================================
