function obj = loadLearnerForCoder(filename,varargin) %#codegen
%LOADLEARNERFORCODER Reconstructs a model from a structure saved in
%   a file created using saveLearnerForCoder. The model can be one of:
%   classification model, regression model and nearest neighbor searcher.
%
%   MDL = LOADLEARNERFORCODER(FILENAME) reconstructs a model from the
%   struct stored in the MAT-file, FILENAME.  The model can be one of:
%   classification model, regression model and nearest neighbor searcher. FILENAME
%   must be a character vector. The MAT-file FILENAME must be created using
%   saveLearnerForCoder. The MAT-file FILENAME is used during code generation to
%   construct a model at compile-time.
%
%   MDL = LOADLEARNERFORCODER(FILENAME,'DataType',T) constructs a version
%   of the model with the precision as specified by T. This can be fixed
%   point precision, or single precision. 
%
%   For a single precision version of the model, the input T is a string or
%   char of 'single'
%
%   For a fixed-point version of the model, it uses the struct stored in the MAT-file, 
%   FILENAME and the data type properties specified by the data type struct T. 
%   The input T must be a struct containing fields that specify fixed-point 
%   data types for inputs, outputs and some internal variables.
%   The function for creating the data type definitions can be autogenerated using
%   the <a href="matlab:doc generateLearnerDataTypeFcn">generateLearnerDataTypeFcn</a> function.
%
%   See also SAVELEARNERFORCODER

%   Copyright 2019-2020 The MathWorks, Inc.

coder.inline('always');
narginchk(1,3);

dtVar = parseAndValidateArgs(varargin{:});

matFile = coder.load(filename);

% classificationStruct accepted for Backwards Compatibility
% compactStruct introduced in 2017a.
isValidMATFile = isfield(matFile,'compactStruct') || isfield(matFile,'classificationStruct') || ...
                       (isfield(matFile,'incrementalTunableStruct') && isfield(matFile,'incrementalNontunableStruct'));

coder.internal.errorIf(~isValidMATFile,...
    'stats:classreg:loadCompactModel:UnsupportedStructForCodegen');

if isfield(matFile,'compactStruct')
    if isempty(dtVar)
        obj = classreg.coderutils.structToModel(coder.const(matFile.compactStruct));
    else
        obj = classreg.coderutils.structToModel(coder.const(matFile.compactStruct),dtVar);
    end
elseif isfield(matFile,'incrementalTunableStruct') && isfield(matFile,'incrementalNontunableStruct') %incremental models
    if isempty(dtVar)
        obj = incremental.coderutils.structToModel(matFile.incrementalTunableStruct,coder.const(matFile.incrementalNontunableStruct));
    else
        validateattributes(dtVar,{'char','string'},{'nonempty'},mfilename,'DataType');
        dtVar = validatestring(dtVar,{'double','single'},mfilename,'DataType'); 
        obj = incremental.coderutils.structToModel(matFile.incrementalTunableStruct,coder.const(matFile.incrementalNontunableStruct),coder.const(dtVar));
    end
else
    obj = classreg.coderutils.structToModel(coder.const(matFile.classificationStruct));
end

end


function dtVar = parseAndValidateArgs(varargin)
coder.inline('always');
coder.internal.prefer_const(varargin);

charConvertedArgs = cell(size(varargin));
[charConvertedArgs{:}] = convertStringsToChars(varargin{:});
if coder.target('MATLAB')
    pnames = {'DataType'};
    dflts =  {     []   };
    dtVar = internal.stats.parseArgs(pnames, dflts, charConvertedArgs{:});
    
    if ~isempty(dtVar) && ~(ischar(dtVar) || isStringScalar(dtVar))
        error(message('stats:classreg:loadCompactModel:BadDataTypeInMATLAB'));
    end
else %codegen
    popts = struct( ...
        'CaseSensitivity', false, ...
        'StructExpand',    false, ...
        'PartialMatching', 'unique',...
        'IgnoreNulls',     true);
    
    params = struct('datatype', uint32(0));
    
    optarg = eml_parse_parameter_inputs(params, popts, charConvertedArgs{:});
    
    dtVar = eml_get_parameter_value(optarg.datatype, [], charConvertedArgs{:});
end

if ~isempty(dtVar)
    validateattributes(dtVar,{'struct','char','string'},{'real'},mfilename,'DataType');
    
    if (ischar(dtVar) || isStringScalar(dtVar))
        dtVar = validatestring(dtVar,{'single'},mfilename);
    end
    
end


end
