function init(varargin)
%INIT  Reinitialize a time series object with new time and data
%
%   INIT(TS,DATA) reinitializes the time series object TS with the data in
%   DATA. A default time vector and object name are used.
%
%   INIT(TS,DATA,TIME) reinitializes the time series object TS with the 
%   data in DATA and the time vector in TIME. A default object name is
%   used. Note that, INIT function will not change the 'Startdate' and
%   'Format' fields in the 'Timeinfo' property.
% 
%   INIT(TS,DATA,TIME,NAME) reinitializes the time series object TS with the 
%   data in DATA, the time vector in TIME, and the name in the string NAME.
%   
%   See also TSDATA.TIMESERIES/TIMESERIES

%   Author(s): James G. Owen, Rong Chen
%   Copyright 1986-2004 The MathWorks, Inc.
%   $Revision: 1.1.6.1 $  $Date: 2004/12/26 21:35:07 $
%

nargchk(nargin,2,4);
this = varargin{1};
varargin = varargin(2:end);
datasrc = [];
timesrc = [];
time = [];
data = [];
quality = [];
name = '';         

%% Parse inputs
switch nargin
    case 2         
        % Accept: timeseries(data),timeseries(name),timeseries(empty)
        if isa(varargin{1},'char')
            name = varargin{1};
            this.Name = name;
            this.send('datachange');
            return
        else % 1st arg is data   
            % Process data vector first   
            [data, datasrc] = localParseData(varargin{1});
            time = localBuildTime(varargin{1});
        end    
    case 3 
        % Accept: timeseries(data, 'name'), timeseries(data, 'time'),
        % timeseries(data, empty)
        % Process data vector first
        [data, datasrc] = localParseData(varargin{1});
        % Deal with second arg
        if isempty(varargin{2}) % 2nd arg is empty
            time = localBuildTime(varargin{1});
        elseif isa(varargin{2},'char') % 2nd arg is a name
            if isvector(varargin{2})
                % a name string
                name = varargin{2};
                time = localBuildTime(varargin{1});
            else
                % possible time vector
                time = mat2cell(varargin{2},ones(size(varargin{2},1),1),size(varargin{2},2));
            end
        % Second argument is time: time vector, cell array, time src or char array    
        elseif isnumeric(varargin{2}) || iscell(varargin{2}) || ...
                isa(varargin{2},'hds.ArrayContainer')
            % Process time vector
            if isa(varargin{2},'hds.ArrayContainer')
                timesrc = varargin{2};
            else
                time = varargin{2};
                if iscell(time)
                    if ~cellfun('isclass',time,'char')
                        time = cell2mat(time);
                    end
                end
            end
        else
            error('timeseries:init:notime',...
                'The second argument must represent the time vector or the time series name')
        end
    case 4 
        % Accept: timeseries(data, time, 'name'),timeseries(data, empty,
        % 'name'),timeseries(data, time, empty),timeseries(data, empty, empty),
        % timeseries(data, time, qual)
        % Process data vector first
        [data, datasrc] = localParseData(varargin{1});
        % Deal with the second arg
        if isempty(varargin{2}) % No time vector, build default
            time = localBuildTime(varargin{1});
        elseif isa(varargin{2},'hds.ArrayContainer')
            timesrc = varargin{2};
        elseif isnumeric(varargin{2}) || iscell(varargin{2})
            time = varargin{2};
        elseif ischar(varargin{2})
            time = {varargin{2}};
        else
            error('Invalid time vector')
        end
        % Deal with the third arg
        if ~isempty(varargin{3})
            if isa(varargin{3},'char') % 3rd arg is a name
                name = varargin{3};
            elseif isnumeric(varargin{3})
                quality = varargin{3};
            else
                error('Invalid 3rd argument')
            end
        end
end

%% Assign either the time vector or the timesrc
if isempty(timesrc)
    
    % Validate time vector
    if isnumeric(time)
       % use try catch to give out errors of possible time and data
       % position switch problem
       try
           time = tsChkTime(time);
       catch
           error(sprintf('%s\nAlso make sure that time vector is the 2nd input argument.',lasterr));
       end
    end

    % Sort time and data vectors. Note this cannot be done if either vector
    % is derived from a data source because the action of sorting would
    % cause time and data to be out of synch
    if ~isempty(datasrc) && ((isnumeric(time) && ~issorted(time)) || ...
            (iscell(time) && issorted(datenum(time)))) 
        error('timeseries:init:unsorted',...
            'Unsorted time vectors cannot be used when ordinate data is defined by a data source')
    elseif ~isempty(datasrc) && isnumeric(time)
        I = tssorttime(time);
    elseif isnumeric(time) && isnumeric(data)
        I = tssorttime(time,data);
    else
        I = (1:length(time))';
    end
   
    if ~isempty(datasrc) && length(I)<length(time)
        error('timeseries:init:unsorted',...
           'Duplicate times are not allowed when ordinate data is defined by a data source')
    end
    
    % Update the grid size to zero if it has changed. It will be reset 
    % by the Time property assignment. Note that explicitly settting the 
    % grid size to a non-zero value will prevent the init method
    % from being 'undone'
    if this.Grid_.Length~=length(time(I))
        this.Grid_.Length = 0;
        this.getContainer('Time').Data = [];
        this.timeInfo.reset([]);
    end
    
    % Assign the time vector
    if iscell(time)
        this.setAbsTime(time(I));	
        % Write new time vector, supressing the datachange event
        utManageDataStorage(this,tsChkTime(this.Time),'Time',true,true);
    else
        %this.Time = time(I);
        utManageDataStorage(this,time(I),'Time',true,true);
    end
else
    setdatasrc(this,timesrc,'Time');
end
    
%% Assign and sort data if both time and data are not from a data src
if ~isempty(datasrc)
    setdatasrc(this,datasrc,'Data');
else
    s = hdsGetSize(data);
    len = length(time);
    % If only the last dimension is aligned with time then assign the 
    % GridFirst properties to refelect this
    if s(1)==len && ~(s(end)==len)
        % Call utManageDataStorage to put the data into timeseriesArray
        % without triggering a datachange event  
        utManageDataStorage(this,hdsReshapeArray(hdsGetSlice(data,...
            [{I} repmat({':'},[1 length(s)-1])]),[length(I) s(2:end)]),...
            'Data',true,true);
    elseif ~(s(1)==len) && s(end)==len
        % If the last dimension of the data equals the time length,
        % assume the last dimension is used to be
        % consistent with the time index.  However, issue a warning to
        % to instruct what to do otherwise (i.e. use the first dimension 
        % as the time index)
%         warning('timeseries:init:gridsetting1',...
%             'The last dimension of data array is the same as the length of the time vector so the last dimension is used as the time index.')
        % this.DataInfo.GridFirst = false;
        % Call utManageDataStorage to put the data into timeseriesArray
        % without triggering a datachange event
        utManageDataStorage(this,hdsReshapeArray(hdsGetSlice(data, ...
            [repmat({':'},[1 length(s)-1]) {I}]), [s(1:end-1) length(I)]),...
            'Data',true,true);
    elseif s(1)==len && s(end)==len
%         warning('timeseries:init:gridsetting2',...
%             'Both the first and last dimensions of data array are the same as the length of the time vector so the first dimension is used as the time index.')
        % Call utManageDataStorage to put the data into timeseriesArray
        % without triggering a datachange event       
        utManageDataStorage(this,hdsReshapeArray(hdsGetSlice(data,...
            [{I} repmat({':'},[1 length(s)-1])]),[length(I) s(2:end)]),...
            'Data', true,true);
    elseif len==1
        % Single time point
        utManageDataStorage(this,data,'Data',true,true);
    else
        error('timeseries:intialize:mismatch',...
            'Mismatch between the size of the time and data vectors')
    end
end

%% Assign the quality vector
if ~isempty(quality)
    utManageDataStorage(this,quality(I),'Quality',true,true);
else
    utManageDataStorage(this,[],'Quality',true,true);
end

%% Assign the name
if isempty(this.Name) && isempty(name) % Initial time series is empty and 
                                       % no name specified
    this.Name = 'default';
elseif ~isempty(name) % Name has been specifed 
    this.Name = name;
end

%warning('backtrace','on')           

%% Fire a datachange event
this.send('datachange')


function time = localBuildTime(data)

% Construct a default time vector from numerical ordinate data or a data
% src

if isa(data,'hds.ArrayContainer')
    try
       s = data.size;
    catch
       error('This syntax is invalid for data sources that so not support getsize')
    end
    if s(1)>1
        time = (0:(s(1)-1))';
    else
%         warning('timeseries:init:buildtime',...
%             'since the first dimension of data array is 1, the last dimension is automatically selected as the time index. if user still wants the first dimension as the time index, please use timeseries(data,1) instead of timeseries(data).')
        time = (0:(s(end)-1))';
    end
elseif isnumeric(data) || isa(data,'tsdata.ArrayAdaptor')
    s = hdsGetSize(data);
    if s(1)>1 && all(s>0)
        time = (0:(s(1)-1))';
    elseif all(s>0)
        time = (0:(s(end)-1))';
    else
        time = zeros(0,1);
    end
else
    error('timeseries:init:indata',...
        'Invalid data type')
end


function [data, datasrc] = localParseData(datainvec)

data = [];
datasrc = [];
if isa(datainvec,'hds.ArrayContainer')
    datasrc = datainvec;
elseif isnumeric(datainvec) ...
        || isa(datainvec,'tsdata.ArrayAdaptor')
    data = datainvec;
else
    error('timeseries:init:nodata',...
        'The first argument must represent the ordinate data')
end

