function x = subsasgn(x,s,y)
% subsasgn  Subscripted assignment for tseries objects.
%
% Syntax
% =======
%
%     x(dates) = values;
%     x(dates,i,j,k,...) = values;
%
% Input arguments
% ================
%
% * `x` [ tseries ] - Tseries object that will be assigned new
% observations.
%
% * `dates` [ numeric ] - Dates for which the new observations will be
% assigned.
%
% * `i`, `j`, `k`, ... [ numeric ] - References to 2nd and higher
% dimensions of the tseries object.
%
% * `values` [ numeric ] - New observations that will assigned at specified
% dates.
%
% Output arguments
% =================
%
% * `x` [ tseries ] - Tseries object with newly assigned observations.
%
% Description
% ============
%
% Example
% ========
% -IRIS Toolbox.
% -Copyright 2007-2012 Jaromir Benes.

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

if isnumeric(s)
    % Simplified syntax: subsasgn(x,dates,y)
    dates = s;
    s = struct();
    s.type = '()';
    s.subs{1} = dates;
end

switch s(1).type
    case {'()' '{}'}
        % Run `lagorlead` to tell if the first reference is a lag/lead. If
        % yes, the startdate of `x` will be adjusted within `lagorlead`.
        [x,s,shift] = lagorlead(x,s);
        if isempty(s)
            return
        end
        % After a lag or lead, only one ()-reference is allowed.
        if length(s) > 1 || ~isequal(s(1).type,'()')
            utils.error('tseries', ...
                ['Invalid subscripted reference or assignment ', ...
                'to tseries object.']);
        end
        x = xxsetdata(x,s,y);
        % Shift start date back.
        if shift ~= 0
            x.start = x.start + shift;
        end
    otherwise
        % Give standard access to public properties.
        x = builtin('subsasgn',x,s,y);
end

end

% Subfunctions.

%**************************************************************************
function x = xxsetdata(x,s,y)

% Pad LHS tseries data with NaNs to comply with references.
% Remove the rows from dates that do not pass the frequency test.
[x,s,dates,freqtest] = xxexpand(x,s);

% Get RHS tseries object data.
if istseries(y)
    y = mygetdata(y,dates);
end

% Convert LHS tseries NaNs to complex if LHS is real and RHS is complex.
if isreal(x.data) && ~isreal(y)
    x.data(isnan(x.data)) = NaN + 1i*NaN;
end

% If RHS has only one row but multiple cols (or size > 1 in other dims),
% tseries is multivariate, and assigned are multiple dates, then expand RHS
% in 1st dimension.
xsize = size(x.data);
ysize = size(y);
if length(y) > 1 && size(y,1) == 1 ...
        && length(s.subs{1}) > 1 ...
        && any(xsize(2:end) > 1)
    n = length(s.subs{1});
    y = reshape(y(ones(1,n),:),[n,ysize(2:end)]);
end

% Report frequency mismatch.
% Remove the rows from RHS that do not pass the frequency test.
ysize = size(y);
if any(~freqtest)
    utils.warning('tseries', ...
        'Date frequency mismatch in assignment to tseries object.');
    if ysize(1) == length(freqtest)
        y = y(freqtest,:);
        y = reshape(y,[size(y,1),ysize(2:end)]);
    end
end

x.data = subsasgn(x.data,s,y);
% Make sure empty tseries have start date set to NaN no matter what.
if isempty(x.data)
    x.start = NaN;
end

% If RHS is empty and first index is ';', then some of the columns have
% been deleted, and the comments must be adjusted accordingly.
if isempty(y) && strcmp(s.subs{1},':')
    x.Comment = subsasgn(x.Comment,s,y);
end

x = mytrim(x);

end
% xxsetdata().

%**************************************************************************
function [x,s,dates,freqtest] = xxexpand(x,s)

% If LHS data are complex, use NaN+NaNi to pad missing observations.
if isreal(x.data)
    unit = 1;
else
    unit = 1 + 1i;
end

% Replace x(dates) with x(dates,:,...,:).
if length(s.subs) == 1
    s.subs(2:ndims(x.data)) = {':'};
end

% Inf and ':' produce the entire tseries range.
% Convert subscripts in 1st dimension from dates to indices.
if isequal(s.subs{1},':') || isequal(s.subs{1},Inf)
    s.subs{1} = ':';
    if isnan(x.start)
        % LHS is empty.
        dates = [];
    else
        dates = x.start + (0 : size(x.data,1)-1);
    end
    freqtest = true(size(dates));
elseif isnumeric(s.subs{1}) && ~isempty(s.subs{1})
    dates = s.subs{1};
    if ~isempty(dates)
        f2 = dates - floor(dates);
        if isnan(x.start)
            % If LHS series is empty tseries, set start date to the minimum
            % date with the same frequency as the first date.
            x.start = min(dates(f2 == f2(1)));
        end
        f1 = x.start - floor(x.start);
        freqtest = abs(f1 - f2) < 1e-2;
        dates(~freqtest) = [];
        s.subs{1} = round(dates - x.start + 1);
    end
else
    dates = [];
    freqtest = [];
end

% Reshape tseries data to reduce number of dimensions if called with
% fewer dimensions. Eg x.data is Nx2x2, and assignment is for x(:,3).
% This mimicks standard Matlab behaviour.
nsubs = length(s.subs);
reshaped = false;
if nsubs < ndims(x.data)
    tempsubs = cell([1,nsubs]);
    tempsubs(:) = {':'};
    tempsize = size(x.data);
    x.data = x.data(tempsubs{:});
    x.Comment = x.Comment(tempsubs{:});
    reshaped = true;
end

% Add NaNs to data when user indices go beyond the data size.
% Add NaNs to 1st dimension when user indices are non-positive.
% Add empty strings for comments to comply with new size.
% This modifies standard Matlab matrix assignment, which produces zeros.
for i = find(~strcmp(':',s.subs))
    % Non-positive index in 1st dimension.
    if i == 1 && any(s.subs{1} < 1)
        n = 1 - min(s.subs{1});
        currentsize = size(x.data);
        currentsize(1) = n;
        x.data = [nan(currentsize)*unit;x.data];
        x.start = x.start - n;
        s.subs{1} = s.subs{1} + n;
    end
    % If index exceeds current size, add NaNs. This is different than
    % standard Matlab behaviour: Matlab adds zeros.
    if any(s.subs{i} > size(x.data,i))
        currentsize = size(x.data);
        currentsize(end+1:nsubs) = 1;
        addsize = currentsize;
        addsize(i) = max(s.subs{i}) - addsize(i);
        x.data = cat(i,x.data,nan(addsize)*unit);
        if i > 1
            % Add an appropriate empty cellstr to comments if tseries data
            % are expanded in 2nd or higher dimensions.
            comment = cell([1,addsize(2:end)]);
            comment(:) = {''};
            x.Comment = cat(i,x.Comment,comment);
        end
    end
end

% Try to reshape tseries data array back.
if reshaped
    try
        x.data = reshape(x.data,tempsize);
        x.Comment = reshape(x.Comment,[1,tempsize(2:end)]);
    catch %#ok<CTCH>
        error('iris:tseries', ...
            'Attempt to grow tseries data array along ambiguous dimension.');
    end
end
end
% xxexpand().