function [c,invalid] = mypseudofunc(c)
% mypseudofunc  [Not a public function] Expand pseudofunctions in IRIS codes.
%
% Backend IRIS function.
% No help provided.

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

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

list = {'diff','dot','movsum','movprod','movavg','difflog'};
list = sprintf('\\<%s\\>|',list{:});
list(end) = '';

invalid = {};
while true
    [start,finish,match] = ...
        regexp(c,['(',list,')(?=\()'],'start','end','match','once');
    if ~isempty(start)
        % Position of the opening bracket.
        open = finish + 1;
        % Find the matching closing bracket.
        [close,inside] = strfun.matchbrk(c,open);
        if ~isempty(inside)
            inside = strrep(inside,' ','');
            switch match
                case 'diff'
                    replace = diffordot(inside,'-');
                case 'dot'
                    replace = diffordot(inside,'*');
                case 'difflog'
                    replace = xxdifflog(inside);
                case 'movsum'
                    replace = xxmovsumormovprod(inside,'+');
                case 'movprod'
                    replace = xxmovsumormovprod(inside,'*');
                case 'movavg'
                    replace = xxmovavg(inside);
            end
        else
            replace = '';
            close = finish;
        end
        if isempty(replace)
            % Report invalid pseudofunction.
            invalid{end+1} = c(start:end); %#ok<AGROW>
        else
            % Wrap the result of the pseudofunction in brackets.
            replace = ['(',replace,')']; %#ok<AGROW>
        end
        c = [c(1:start-1),replace,c(close+1:end)];
    else
        break
    end
end

end

% Subfunctions.

%**************************************************************************
function [expression,shift] = xxparsefunc(c,defaultShift)
% xxparsefunc  Parse pseudofunctions.
%     pseudofunc(expression)
%     pseudofunc(expression,k)

shift = defaultShift;
tokens = regexp(c,'^(.*?)(,[\+\-]?\d+)?$','tokens','once');
if isempty(tokens) || isempty(tokens{1})
    expression = '';
    return
end
expression = tokens{1};
if ~isempty(tokens{2})
    tokens{2}(1) = '';
    try
        shift = eval(tokens{2});
    catch %#ok<CTCH>
        expression = '';
        return
    end
end

end
% xxparsefunc().

%**************************************************************************
function [c,k] = diffordot(c,operator)

[c,k] = xxparsefunc(c,-1);
if ~isempty(c)
    c = ['(',c,')',operator,'(',xxshift(c,k),')'];
end

end
% xxdiffordot().

%**************************************************************************
function [c,k] = xxdifflog(c)

[c,k] = xxparsefunc(c,-1);
if ~isempty(c)
    c = ['log(',c,')-log(',xxshift(c,k),')'];
end

end
% xxdifflog().

%**************************************************************************
function [c,k] = xxmovsumormovprod(c,operator)

[expression,k] = xxparsefunc(c,-4);
if ~isempty(c)
    if k > 0
        shiftVec = 1 : k-1;
    else
        k = -k;
        shiftVec = -(1 : k-1);
    end
    c = ['(',expression,')'];
    for i = shiftVec
        c = [c,operator,'(',xxshift(expression,i),')']; %#ok<AGROW>
    end
end

end
% xxmovsumormovprod().

%**************************************************************************
function c = xxmovavg(c)

[c,shift] = xxmovsumormovprod(c,'+');
c = sprintf('(%s)/%g',c,abs(shift));

end
% xxmovavg().

%**************************************************************************
function c = xxshift(c,k)

replacefunc = @oneShift_; %#ok<NASGU>
c = regexprep(c, ...
    '(\<[A-Za-z]\w*\>)(\{[\+\-]?\d+\})?(?!\()', ...
    '${replacefunc($1,$2)}');
    function x = oneShift_(name,shift)
        if isempty(shift)
            shift = sprintf('{%g}',k);
        else
            shift = sscanf(shift,'{%g}');
            if ~isnumeric(shift) || length(shift) ~= 1
                shift = '{NaN}';
            else
                shift = sprintf('{%g}',shift+k);
            end
        end
        x = [name,shift];
    end

end
% xxshift().
