function [c,s,leftover,multiple,undef] = mysubstitute(c)
% mysubsitutte  [Not a public function] Expand and replace substitutions in preparsed codes.
%
% Backend IRIS function.
% No help provided.

% -IRIS Toolbox.
% -Copyright (c) 2007-2012 Jaromir Benes.

s = struct();
leftover = {}; %#ok<NASGU>
multiple = {};
undef = {};

%**************************************************************************

% Read substitution blocks.
[c,blk] = xxreadblocks(c);

% Read names and bodies of individual substitutions. Do this in
% individual subs blocks separately to catch syntax errors such as the
% last subs definition not finished by a semicolon.
name = {};
body = {};
leftover = {};
for i = 1 : length(blk)
    [name,body,temp] = xxreadsubs(blk{i},name,body);
    if ~isempty(temp)
        leftover{end+1} = temp; %#ok<AGROW>
    end
end
if ~isempty(leftover)
    return
end

% Check uniqueness of substitution names.
multiple = strfun.nonunique(name);
if ~isempty(multiple)
    return
end

% Expand substitutions.
[c,body] = xxexpand(c,name,body);

% Check for the occurence of undefined (unexpanded) or unresolved
% substitutions in the rest of the code. Unresolved substitutions can
% occur also because of wrong order of their definitions.
undef = xxchkundefined(c);
if ~isempty(undef)
    return
end

s = cell2struct(body,name,2);

end

% Subfunctions.

%**************************************************************************
function [c,blk] = xxreadblocks(c)

blk = {};
% Read the blocks one by one to preserve their order in the
% model code. Remove the substitution blocks from the code.
while true
    [tok,start,finish] = ...
        regexp(c,'!substitutions(.*?)(?=![^!\s]|$)', ...
        'tokens','start','end','once');
    if isempty(start)
        break
    end
    blk{end+1} = strtrim(tok{1}); %#ok<AGROW>
    c(start:finish) = '';
end

end
% xxreadblocks().

%**************************************************************************
function [name,body,leftover] = xxreadsubs(b,name,body)

% Read substitution names and bodies. Again, do it one by one to
% preserve their order.
while true
    [tok,start,finish] = ...
        regexp(b,'(\<[a-zA-Z]\w*\>)\s*:?\s*=\s*([^;]*)\s*;', ...
        'tokens','start','end','once');
    if isempty(start)
        break
    end
    name{end+1} = tok{1}; %#ok<AGROW>
    body{end+1} = tok{2}; %#ok<AGROW>
    b(start:finish) = '';
end
leftover = strtrim(b);

end
% xxreadsubs().

%**************************************************************************
function [c,body] = xxexpand(c,name,body)

% Expand substitutions in other substitutions first.
n = length(name);
pattern = cell(1,n);
for i = 1 : n
    pattern{i} = ['$',name{i},'$'];
    for j = i+1 : n
        body{j} = strrep(body{j},pattern{i},body{i});
    end
end
% Expand substitutions in the rest of the code. Proceed backward so
% that unresolved substitutions in substitution bodies (pointing to
% substitutions defined later) remain unresolved and can be caught as
% an error.
for i = n : -1 : 1
    c  = strrep(c,pattern{i},body{i});
end

end
% xxexpand().

%**************************************************************************
function undef = xxchkundefined(c)
% chkundefined  Check for undefined substitutions.

undef = regexp(c,'\$\<[A-Za-z]\w*\>\$','match');
if ~isempty(undef)
    undef = unique(undef);
end

end
% xxchkundefinedsubs().