% TSDATA time-series object class constructor.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DESCRIPTION: TSDATA time-series object class constructor.
%              Create a time-series data object. If the time-series object
%              is determined to be evenly sampled, no x vector is stored.
%
% SUPER CLASSES: data2D < ltpda_data < ltpda_nuo < ltpda_obj
%
% CONSTRUCTORS:
%
%       ts = tsdata()        - creates a blank time-series object
%       ts = tsdata(y)       - creates a time-series object with the given
%                              y-data.
%       ts = tsdata(x,y)     - creates a time-series object with the given
%                              (x,y)-data. The sample rate is then set using
%                              the private method fitfs(). This computes the
%                              best sample rate that fits the data. If the
%                              data is evenly sampled, the sample rate is set
%                              as 1/median(diff(x)) and the x data is then
%                              not stored (empty vector).
%       ts = tsdata(y,fs)    - creates a time-series object with the given
%                              y-data. The data is assumed to be evenly sampled
%                              at the given sample rate with the first sample
%                              assigned time 0. No x vector is created.
%       ts = tsdata(y,t0)    - creates a time-series object with the given
%                              y-data. The data are assumed to be evenly
%                              sampled at 1Hz. The first sample is assumed to
%                              be at 0s offset from t0 and t0 is set to the
%                              user specified value.
%       ts = tsdata(x,y,fs)  - creates a time-series object with the given
%                              x/y data vectors. The sample rate is set to
%                              fs.
%       ts = tsdata(x,y,t0)  - creates a time-series object with the given
%                              x/y data vectors. The t0 property is set to
%                              the supplied t0 and the sample rate is
%                              computed from the x vector using fitfs(). If
%                              the data is found to be evenly sampled, the
%                              x vector is discarded.
%       ts = tsdata(y,fs,t0) - creates a time-series object with the given
%                              y-data. The data are assumed to be evenly
%                              sampled at fs and the first sample is
%                              assumed to be taken at time t0. No x vector
%                              is generated.
%       ts = tsdata(x,y,fs,t0)-creates a time-series object with the given
%                              x-data, y-data, fs and t0.
%
% VERSION:  $Id: tsdata.m,v 1.86 2011/11/04 21:11:48 mauro Exp $
%
% SEE ALSO: tsdata, fsdata, xydata, cdata, data2D, data3D, xyzdata
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

classdef (Hidden = true) tsdata < data2D
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                            Property definition                            %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  %---------- Public (read/write) Properties  ----------
  properties
  end
  
  %---------- Protected read-only Properties ----------
  properties (GetAccess = public, SetAccess = protected)
    t0      = time(0); % time-stamp of the first data sample in UTC format
    toffset = 0;       % time offset from t0 to the first data sample in milliseconds
    fs      = NaN;     % sample rate of data
    nsecs   = 0;       % the length of this time-series in seconds
  end
  
  %---------- Private Properties ----------
  properties (GetAccess = protected, SetAccess = protected)
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                          Check property setting                           %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods
    function set.t0(obj, val)
      if (~isa(val, 'time') && ~ischar(val) && ~isnumeric(val))|| isempty(val)
        error('### The value for the property ''t0'' must be a string, a number or a time object');
      end
      if ischar(val) || isnumeric(val)
        obj.t0 = time(val);
      else
        obj.t0 = val;
      end
    end
    function set.fs(obj, val)
      if ~isnumeric(val) || isempty(val) || ~isreal(val) || val < 0
        error('### The value for the property ''fs'' must be a real positive number');
      end
      obj.fs = val;
    end
    function set.nsecs(obj, val)
      if ~isnumeric(val) || isempty(val) || ~isreal(val) || val < 0
        error('### The value for the property ''nsecs'' must be a real positive number');
      end
      obj.nsecs = val;
    end
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                Constructor                                %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods
    function obj = tsdata(varargin)
      
      switch nargin
        case 0
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%   no inputs   %%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          
        case 1
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%   one input   %%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          
          if isa(varargin{1}, 'tsdata')
            %%%%%%%%%%   data = tsdata(tsdata-object)   %%%%%%%%%%
            %----------- Copy tsdata Object   %%%%%%%%%%
            obj = copy(varargin{1}, 1);
            
          elseif isstruct(varargin{1})
            %%%%%%%%%%   data = tsdata(struct)   %%%%%%%%%%
            obj = fromStruct(obj, varargin{1});
            
          elseif isnumeric(varargin{1})
            %%%%%%%%%%   data = tsdata(y-vector)   %%%%%%%%%%
            %----------- y vector
            obj.setY(varargin{1});
            obj.fs = 1;
            
          else
            error('### Unknown single argument constructor.');
          end
          
        case 2
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%   two input   %%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          
          if numel(varargin{1}) > numel(varargin{2}) && numel(varargin{2}) == 1 && ~isa(varargin{2}, 'time')
            %%%%%%%%%%   data = tsdata(y-vector, fs)   %%%%%%%%%%
            % tsdata(y,fs)
            obj.y  = varargin{1};
            obj.fs = varargin{2};
            
          elseif isa(varargin{1}, 'org.apache.xerces.dom.DeferredElementImpl') && ...
              isa(varargin{2}, 'history')
            %%%%%%%%%%   obj = tsdata(DOM node, history-objects)   %%%%%%%%%%
            obj = fromDom(obj, varargin{1}, varargin{2});
            
          elseif numel(varargin{1}) == numel(varargin{2})
            %%%%%%%%%%   data = tsdata(x-vector, y-vector)   %%%%%%%%%%
            % tsdata(x,y)
            if numel(varargin{1}) > 1
              [fs_fitfs,t0_fitfs,fitted] = tsdata.fitfs(varargin{1});
              obj.fs = fs_fitfs;
              if fitted
                obj.setXY(varargin{1} - varargin{1}(1), varargin{2});
              else
                obj.setY(varargin{2});
              end
                obj.toffset = varargin{1}(1) * 1000;
            else
              obj.setXY(varargin{1} - varargin{1}(1), varargin{2});
              obj.fs = 1;
              t0_fitfs = 0;
              obj.toffset = varargin{1}(1) * 1000;
            end
            obj.t0 = time(t0_fitfs);
            
          elseif isa(varargin{2}, 'time')
            %%%%%%%%%%   data = tsdata(y-vector, t0)   %%%%%%%%%%
            % tsdata(y,t0)
            obj.setY(varargin{1});
            obj.fs = 1;
            obj.t0 = varargin{2};
            
          else
            error('### Unknown two argument constructor.');
          end
        case 3
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%   three input   %%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          
          if numel(varargin{1}) == numel(varargin{2}) && numel(varargin{3}) == 1 && ~isa(varargin{3}, 'time')
            %%%%%%%%%%   data = tsdata(x-vector, y-vector, fs)   %%%%%%%%%%
            % tsdata(x,y,fs)
            obj.fs = varargin{3};
            
            [fs_fitfs,t0_fitfs,fitted] = tsdata.fitfs(varargin{1});
            obj.t0 = t0_fitfs;
            if fitted
              obj.setXY(varargin{1} - varargin{1}(1), varargin{2});
            else
              if abs(fs_fitfs - obj.fs) > 2*eps(obj.fs)
                error('The requested sample rate (%g) does not match the sample rate computed from the input x values (%g)', obj.fs, fs_fitfs);
              end
              obj.setY(varargin{2});
            end
            obj.toffset = varargin{1}(1) * 1000;
            
          elseif numel(varargin{1}) == numel(varargin{2}) && isa(varargin{3}, 'time')
            %%%%%%%%%%   data = tsdata(x-vector, y-vector, t0)   %%%%%%%%%%
            % tsdata(x,y,t0)
            [fs_fitfs,t0_fitfs,fitted] = tsdata.fitfs(varargin{1});
            obj.fs = fs_fitfs;
            obj.t0 = varargin{3} + t0_fitfs;
            if fitted
              obj.setXY(varargin{1} - varargin{1}(1), varargin{2});
            else
              obj.setY(varargin{2});
            end
            obj.toffset = varargin{1}(1) * 1000;
            
          elseif numel(varargin{1}) > numel(varargin{2}) && isa(varargin{3}, 'time')
            %%%%%%%%%%   data = tsdata(y-vector, fs, t0)   %%%%%%%%%%
            % tsdata(y,fs,t0)
            obj.setY(varargin{1});
            obj.fs = varargin{2};
            obj.t0 = varargin{3};
          else
            error('### Unknown three argument constructor.');
          end
        case 4
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%   four input   %%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          
          if numel(varargin{1}) == numel(varargin{2}) && numel(varargin{3}) == 1 && isa(varargin{4}, 'time')
            %%%%%%%%%%   data = tsdata(x-vector, y-vector, fs, t0)   %%%%%%%%%%
            obj.fs = varargin{3};
            
            [fs_fitfs,t0_fitfs,fitted] = tsdata.fitfs(varargin{1});
            if fitted
              obj.setXY(varargin{1} - varargin{1}(1), varargin{2});
            else
              if abs(fs_fitfs - obj.fs) > 2*eps(obj.fs)
                error('The requested sample rate (%g) does not match the sample rate computed from the input x values (%g)', obj.fs, fs_fitfs);
              end
              obj.setY(varargin{2});
            end
            obj.toffset = varargin{1}(1) * 1000;
            obj.fs = fs_fitfs;
            obj.t0 = varargin{4}+t0_fitfs;
          else
            error('### Unknown four argument constructor.');
          end
        otherwise
          error('### Unknown number of constructor arguments.');
      end
      
      % Now we can set nsecs
      if ~isempty(obj.x)
        % Then we have unevenly sampled data and the data duration
        % is taken as x(end) - x(1);
        obj.setNsecs(obj.x(end)-obj.x(1) + 1/obj.fs);
      else
        if ~isempty(obj.y)
          % Then the data is evenly sampled and the
          % duration of the data is easily computed.
          Ndata = length(obj.y);
          obj.setNsecs(Ndata / obj.fs);
        end
      end
      
    end % End constructor
  end % End public methods
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                              Methods  (Public, hidden)                    %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods (Hidden = true)
    varargout = attachToDom(varargin)
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                              Methods (protected)                          %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods (Access = protected)
    varargout = fromStruct(varargin)
    varargout = fromDom(varargin)
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                               Methods (private)                           %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods (Access = private)
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                            Methods (static)                               %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  methods (Static)
    varargout = fitfs(varargin)
    
    function out = VEROUT()
      out = '$Id: tsdata.m,v 1.86 2011/11/04 21:11:48 mauro Exp $';
    end
    
    function ii = getInfo(varargin)
      ii = utils.helper.generic_getInfo(varargin{:}, 'tsdata');
    end
    
    function out = SETS()
      out = {'Default'};
    end
    
    function out = getDefaultPlist(set)
      switch lower(set)
        case 'default'
          out = plist();
        otherwise
          error('### Unknown set [%s]', set');
      end
    end
    
    function obj = initObjectWithSize(n,m)
      obj = tsdata.newarray([n m]);
    end
    
  end % End static methods
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                         Methods (static, private)                         %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods (Static, Access = private)
  end % End static, private methods
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                         Methods (static, hidden)                          %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods (Static = true, Hidden = true)
    varargout = loadobj(varargin)
    varargout = update_struct(varargin);
  end
  
end % End classdef
