function template = generateFunctionSignaturesTemplate(varargin)
% INTERNAL MathWorks-only FUNCTION: SUBJECT TO CHANGE WITHOUT NOTICE.
% Copyright 2017 The MathWorks, Inc.
%
% For the given functions, generate a template signature file.
    functions = varargin;

    template = containers.Map();
    
    template('_schemaVersion') = "1.0.0";
    
    for idx = 1:numel(functions)
        f = char(functions(idx));
        sig = compiler.internal.getSig(f);

        % If the file contains a syntax error, the signature will be empty.
        if(isempty(sig))
            error(message('CompilerSDK:deploytool:FUNCTION_SIGNATURE_ERROR',f))
        else
            [~,name,~] = fileparts(f);

            inputs = generateParamTemplates(sig.vhInputs);

            outputs = generateParamTemplates(sig.vhOutputs);
            
            helpText = builtin('helpfunc',f);
            
            template(char(name)) = struct('inputs',  {inputs},...
                                          'outputs', {outputs},...
                                          'purpose', helpText);
        end
    end

     template = [ '// Function Signatures', newline,...
                  '// To optionally specify argument types and/or sizes, search for "type"', newline,...
                  '// and insert the appropriate specifiers inside the brackets. For example:', newline,...
                  '//', newline,...
                  '//    "type": ["double", "size=1,1"]', newline,...
                  '//', newline,...
                  '// To modify function help text, search for "purpose" and edit the values.', newline,...
                  '//', newline,...
                  '// JSON-formatted text below this line.', newline,...
                  jsonPrettyPrint(jsonencode(template))
                ];
end

function template = generateParamTemplates(names)
%Generates param template for a list of parameter names.  NAMES must be a cell vector    
    assert(iscell(names));
    template = struct('name', names, 'type', repmat({{}}, size(names)));
    template = forcejsonarray(template);
end

function array = forcejsonarray(a)
%jsonencode always encodes 1x1 MATLAB arrays as scalars.  
%Wrapping in an additional array so it will be encoded
%as a JSON array instead
    if(numel(a) == 1) 
        array = {a};
    else
        array = a;
    end
end

function out = jsonPrettyPrint(in)
% Pretty-prints JSON text
    
indentLevel=0;
out = '';
in = strip(char(in));

separators = ['{', '}', '[', ']', ',', '"', ':', '\'];

indexes = find(ismember(in, separators));

instring = false;
lastindex = 1;
ignoreNext = false;
for j=1:numel(indexes)
    i = indexes(j);
    
    s = '';
    sep = in(i:i);
    
    if(ignoreNext)
        ignoreNext = false;
        continue;
    end

    if(strcmp(sep, '\'))
        if(ismember(in(i+1), ['\', '"']))
            ignoreNext = true;
            continue;
        end
    end
    
    if(strcmp(sep, '"'))
        instring = ~instring;
        continue;
    end
    
    if(instring)
        continue;
    end
    
    if(strcmp(sep,'{') || strcmp(sep, '['))
        % Don't add extra spaces or lines to '[]'
        if(strcmp(sep, '[') && strcmp(in(i+1), ']'))
            ignoreNext = true;
            continue;
        end
        indentLevel = indentLevel+1;
        s = [sep newline indent(indentLevel)];
    elseif (strcmp(sep,'}') || strcmp(sep, ']'))
        indentLevel = indentLevel-1;
        s = [newline indent(indentLevel) sep];
    elseif (strcmp(sep, ','))
        s = [sep newline indent(indentLevel)];
    elseif (strcmp(sep, ':'))
        s = [ sep ' '];
    end
    
    if(lastindex < i)
        out = [out in(lastindex:i-1) s]; %#ok
    else
        out = [out s]; %#ok
    end
    
    lastindex = i+1;
end

out = [out in(lastindex:numel(in))];

end

function spaces = indent(level)
    % Four spaces per indent level
    spaces = blanks(level*4);
end
