function [THIS,ASGND] = assign(THIS,varargin)
% assign  [Not a public function] Assign values to names in metaobj.
%
% Backend IRIS function.
% No help provided.

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

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

persistent ASSIGNPOS ASSIGNRHS STDCORRPOS STDCORRRHS;

if isempty(varargin)
    return
end

level = false;
growth = false;
if ischar(varargin{1})
    if strcmp(varargin{1},'-level')
        level = true;
        varargin(1) = [];
    elseif strcmp(varargin{1},'-growth')
        growth = true;
        varargin(1) = [];
    end
end

% Number of input arguments with the growth label removed.
n = length(varargin);

% `Assign` and `stdcorr` are logical indices of values that have been
% assigned.
Assign = false(size(THIS.name));
stdcorr = false(size(THIS.stdcorr));

if isempty(varargin)
    reset_();
    ASGND = cell([1,0]);
    return
    
elseif n == 1 && isa(varargin{1},'metaobj')
    % Assign from another model object. The names, name types, and number of
    % parameterisations must match.
    equalNames = isequal(THIS.name,varargin{1}.name);
    equalTypes = isequal(THIS.nametype,varargin{1}.nametype);
    equalAlter = size(THIS.Assign,3) == size(varargin{1}.Assign,3);
    if equalNames && equalAlter
        THIS.Assign = varargin{1}.Assign;
        THIS.stdcorr = varargin{1}.stdcorr;
        ASGND = Inf;
        return
    elseif ~equalNames || ~equalTypes
        utils.error('model', ...
            'Cannot assign from a model object ', ...
            'with different names or name types.');
    else
        utils.error('model', ...
            'Cannot assign from a model object ', ...
            'with different number of paratemeterisations.');
    end
    
elseif n == 1 && isnumeric(varargin{1})
    % m = assign(m,array).
    if isempty(ASSIGNPOS) && isempty(STDCORRPOS)
        utils.error('model', ...
            ['ASSIGN must be initiliased before used ', ...
            'with a single numeric input.']);
    end
    Assign(ASSIGNPOS) = true;
    stdcorr(STDCORRPOS) = true;
    THIS.Assign(1,ASSIGNPOS,:) = varargin{1}(ASSIGNRHS);
    THIS.stdcorr(1,STDCORRPOS,:) = varargin{1}(STDCORRRHS);
    if nargout == 1
        return
    end
    
elseif n <= 2 && iscellstr(varargin{1})
    % assign(m,cellstr) initialises quick-assign function.
    % m = assign(m,cellstr,array)
    list = varargin{1}(:).';
    [ASSIGNPOS,STDCORRPOS] = mynameposition(THIS,list);
    ASSIGNRHS = ~isnan(ASSIGNPOS);
    ASSIGNPOS = ASSIGNPOS(ASSIGNRHS);
    STDCORRRHS = ~isnan(STDCORRPOS);
    STDCORRPOS = STDCORRPOS(STDCORRRHS);
    if n == 1
        return
    else
        if length(varargin{2}) == 1 && length(list) > 1
            varargin{2} = varargin{2}(1, ...
                ones([1,length(list)]),ones([1,size(THIS.Assign,3)]));
        end
        if (growth || level) && any(imag(varargin{2}(:)) ~= 0)
            utils.error('model', ...
                ['You may only assign real numbers ', ...
                'when using the ''-level'' or ''-growth'' options.']);
        end
        if growth
            varargin{2}(ASSIGNRHS) = real(THIS.Assign(1,ASSIGNPOS,:)) ...
                + 1i*varargin{2}(ASSIGNRHS);
        elseif level
            varargin{2}(ASSIGNRHS) = varargin{2}(ASSIGNRHS) ...
                + 1i*imag(THIS.Assign(1,ASSIGNPOS,:));
        end
        if any(ASSIGNRHS)
            Assign(ASSIGNPOS) = true;
            THIS.Assign(1,ASSIGNPOS,:) = varargin{2}(ASSIGNRHS);
        end
        if any(STDCORRRHS)
            stdcorr(STDCORRPOS) = true;
            THIS.stdcorr(1,STDCORRPOS,:) = varargin{2}(STDCORRRHS);
        end
        reset_();
    end
    
elseif n == 1 && isstruct(varargin{1})
    % m = assign(m,struct).
    c = fieldnames(varargin{1});
    [assignpos,stdcorrpos] = mynameposition(THIS,c);
    for i = find(~isnan(assignpos))
        x = varargin{1}.(c{i});
        if (growth || level) && any(imag(x(:)) ~= 0)
            utils.error('model', ...
                ['You may only assign real numbers ', ...
                'when using the ''level'' or ''growth'' labels.']);
        end
        if growth
            x = real(THIS.Assign(1,assignpos(i),:)) + 1i*x;
        elseif level
            x = x + 1i*imag(THIS.Assign(1,assignpos(i),:));
        end
        THIS.Assign(1,assignpos(i),:) = x;
        Assign(assignpos(i)) = true;
    end
    for i = find(~isnan(stdcorrpos))
        THIS.stdcorr(1,stdcorrpos(i),:) = varargin{1}.(c{i});
        stdcorr(stdcorrpos(i)) = true;
    end
    reset_();
    if nargout == 1
        return
    end
    
elseif iscellstr(varargin(1:2:end))
    % m = assign(m,name,value,name,value,...)
    Assign = false(1,size(THIS.Assign,2));
    stdcorr = false(1,size(THIS.stdcorr,2));
    for j = 1 : 2 : length(varargin)
        if isempty(varargin{j})
            continue
        end
        [assignindex,stdcorrindex] = mynameposition(THIS,varargin{j});
        for i = find(assignindex).'
            if (growth || level) && any(imag(varargin{j+1}(:)) ~= 0)
                utils.error('model', ...
                    ['You may only assign real numbers ', ...
                    'when using the ''level'' or ''growth'' labels.']);
            end
            if growth
                varargin{j+1} = real(THIS.Assign(1,i,:)) + 1i*varargin{j+1};
            elseif level
                varargin{j+1} = varargin{j+1} + 1i*imag(THIS.Assign(1,i,:));
            end
            THIS.Assign(1,i,:) = varargin{j+1};
            Assign(i) = true;
        end
        if any(stdcorrindex)
            THIS.stdcorr(1,stdcorrindex,:) = varargin{j+1};
            stdcorr(stdcorrindex) = true;
        end
    end
    reset_();
    
else
    % Throw an invalid assignment error.
    utils.error(class(THIS), ...
        'Invalid assignment to a %s object.', ...
        class(THIS));
end


% Put together list of parameters, steady states, std deviations, and
% correlations that have been assigned.
if nargout > 1
    ASGND = THIS.name(Assign);
    ne = sum(THIS.nametype == 3);
    elist = THIS.name(THIS.nametype == 3);
    ASGND = [ASGND, ...
        regexprep(elist(stdcorr(1:ne)),'^.','std_$0','once')];
    pos = find(tril(ones(ne),-1) == 1);
    temp = zeros(ne);
    temp(pos(stdcorr(ne+1:end))) = 1;
    [i,j] = find(temp == 1);
    for k = 1 : length(i)
        ASGND{end+1} = ['corr_',elist{i(k)},'_',elist{j(k)}]; %#ok<AGROW>
    end
end

% Nested functions.

    function reset_()
        ASSIGNPOS = [];
        ASSIGNRHS = [];
        STDCORRPOS = [];
        STDCORRRHS = [];
    end

end
