% TIMESPAN timespan object class constructor.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DESCRIPTION:  TIMESPAN timespan object class constructor.
%               Create a timespan object.
%
% CONSTRUCTORS:
%
%       ts = timespan()
%       ts = timespan('file_name.mat');
%       ts = timespan('file_name.xml');
%       ts = timespan( time,       time)
%       ts = timespan(time,       '14:00:05')
%       ts = timespan('14:00:00',  time)
%       ts = timespan('14:00:00', '14:00:05')
%       ts = timespan(30000, 50000)
%       ts = timespan(20000, 30000, 'HH:MM:SS')
%       ts = timespan(plist)
%
% SUPPORTED TIMEFORMATS:
%
%       dd-mm-yyyy HH:MM:SS             yyyy - year     (000-9999)
%       dd.mm.yyyy HH:MM:SS             mm   - month    (1-12)
%       dd-mm-yyyy HH:MM:SS.FFF         dd   - day      (1-31)
%       dd.mm.yyyy HH:MM:SS.FFF         HH   - hour     (00-24)
%       HH:MM:SS dd-mm-yyyy             MM   - minutes  (00-59)
%       HH:MM:SS dd.mm.yyyy             SS   - seconds  (00-59)
%       HH:MM:SS.FFF dd-mm-yyyy         FFF  - milliseconds (000-999)
%       HH:MM:SS.FFF dd.mm.yyyy
%       MM:SS
%       MM:SS.FFF
%
% <a href="matlab:utils.helper.displayMethodInfo('timespan', 'timespan')">Parameters Description</a>
%
% VERSION:     $Id: timespan.m,v 1.89 2011/08/22 05:56:30 hewitson Exp $
%
% SEE ALSO:    ltpda_uoh, ltpda_uo, ltpda_obj, plist
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

classdef timespan < ltpda_uoh

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                            Property definition                            %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  %---------- Public (read/write) Properties  ----------
  properties
  end

  %---------- Protected read-only Properties ----------
  properties (SetAccess = protected)
    startT     = time(0); % Start time of the time span. (time-object)
    endT       = time(0); % End time of the time span.   (time-object)
    interval   = ''; % Interval between start/end time
  end

  %---------- Constant Properties ----------
  properties (Constant = true)
    timeformat; % timeformat of the time span (see preferences)
    timezone; % timezone of the time span (see preferences)
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                        Constant Property Methods                          %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
  methods
    function value = get.timezone(obj)
      p = getappdata(0, 'LTPDApreferences');
      value = char(p.getTimePrefs.getTimeTimezone);
      if ischar(value)
        value = java.util.TimeZone.getTimeZone(value);
      end
    end

    function value = get.timeformat(obj)
      p = getappdata(0, 'LTPDApreferences');
      value = char(p.getTimePrefs.getTimestringFormat);
    end
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                        Dependent Property Methods                         %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  methods
    function value = get.interval(obj)
      value = computeInterval(obj);
    end
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                          Check property setting                           %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  methods
    function set.startT(obj, val)
      if ~isa(val, 'time')
        error('### The value for the property ''startT'' must be a time-object.\nBut it is from the class [%s]',class(val));
      end
      obj.startT = val;
    end
    function set.endT(obj, val)
      if ~isa(val, 'time')
        error('### The value for the property ''endT'' must be a time-object.\nBut it is from the class [%s]',class(val));
      end
      obj.endT = val;
    end
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                Constructor                                %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  methods
    function obj = timespan(varargin)

      import utils.const.*
      utils.helper.msg(msg.OMNAME, 'running %s/%s', mfilename('class'), mfilename);

      % Collect all timespan objects
      [ts, dummy, rest] = utils.helper.collect_objects(varargin(:), 'timespan');

      if isempty(rest) && ~isempty(ts)
        % Do copy constructor and return
        utils.helper.msg(msg.OPROC1, 'copy constructor');
        obj = copy(ts, 1);
        for kk=1:numel(obj)
          obj(kk).addHistory(timespan.getInfo('timespan', 'None'), [], [], obj(kk).hist);
        end
        return
      end

      switch nargin
        case 0
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%   no input   %%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          utils.helper.msg(msg.OPROC1, 'empty constructor');
          obj.addHistory(timespan.getInfo('timespan', 'None'), plist(), [], []);

        case 1
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%   one input   %%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

          if ischar(varargin{1})

            %%%%%%%%%%   ts = timespan('foo.mat')   %%%%%%%%%%
            %%%%%%%%%%   ts = timespan('foo.xml')   %%%%%%%%%%
            utils.helper.msg(msg.OPROC1, 'constructing from file %s', varargin{1});
            obj = fromFile(obj, varargin{1});

          elseif isstruct(varargin{1})
            %%%%%%%%%%   ts = time(struct)   %%%%%%%%%%

            utils.helper.msg(msg.OPROC1, 'constructing from struct');
            obj = fromStruct(obj, varargin{1});

          elseif isa(varargin{1}, 'plist')
            %%%%%%%%%%   ts = time(plist)   %%%%%%%%%%

            pl = varargin{1};

            if pl.isparam('filename')
              %-----------------------------------------------------
              %--- Construct from file
              %-----------------------------------------------------
              utils.helper.msg(msg.OPROC1, 'constructing from file %s', pl.find('filename'));
              obj = fromFile(obj, varargin{1});

            elseif pl.isparam('hostname') || pl.isparam('conn')
              %-----------------------------------------------------
              %--- Construct from repository
              %-----------------------------------------------------
              utils.helper.msg(msg.OPROC1, 'constructing from repository %s', pl.find('hostname'));
              obj = obj.fromRepository(pl);

            elseif (pl.isparam('startT') || pl.isparam('start')) && ...
                (pl.isparam('endT')   || pl.isparam('end'))
              %-----------------------------------------------------
              %--- Construct from start and end times
              %-----------------------------------------------------
              utils.helper.msg(msg.OPROC1, 'constructing from start/end times');
              obj = obj.fromTimespanDef(pl);

            elseif pl.isparam('built-in')
              %-----------------------------------------------------
              %--- Construct from built-in model
              %-----------------------------------------------------
              utils.helper.msg(msg.OPROC1, 'constructing from built-in model');
              obj = fromModel(obj, pl);

            else
              obj.setObjectProperties(pl);
              obj.addHistory(timespan.getInfo('timespan', 'None'), pl, [], []);
            end

          else
            error('### Unknown single argument constructor.');
          end

        case 2
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%   two input   %%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

          if (ischar(varargin{1}) || isa(varargin{1}, 'time') || isnumeric(varargin{1})) && ...
              (ischar(varargin{2}) || isa(varargin{2}, 'time') || isnumeric(varargin{2}))
            %%%%%%%%%%  ts = timespan('14:00:00', '14:00:05')   %%%%%%%%%%
            %%%%%%%%%%  ts = timespan('14:00:00', time)         %%%%%%%%%%
            %%%%%%%%%%  ts = timespan(time, time)               %%%%%%%%%%
            %%%%%%%%%%  ts = timespan(time, '14:00:05')         %%%%%%%%%%
            utils.helper.msg(msg.OPROC1, 'constructing from start/end time');
            pli = plist('startT', varargin{1}, 'endT', varargin{2});
            obj = obj.fromTimespanDef(pli);

          elseif (isa(varargin{1}, 'database') || isa(varargin{1}, 'java.sql.Connection')) && isnumeric(varargin{2})
            %%%%%%%%%%  f = timespan(database, IDs)   %%%%%%%%%%
            utils.helper.msg(msg.OPROC1, 'retrieve from repository');
            obj = obj.fromRepository(plist('conn', varargin{1}, 'id', varargin{2}));

          elseif isa(varargin{1}, 'timespan') && isa(varargin{2}, 'plist') && isempty(varargin{2}.params)
            %%%%%%%%%%  f = timespan(timespan-object, <empty plist>)   %%%%%%%%%%
            obj = timespan(varargin{1});

          elseif isa(varargin{1}, 'org.apache.xerces.dom.DeferredElementImpl') && ...
                 isa(varargin{2}, 'history')
            %%%%%%%%%%   obj = timespan(DOM node, history-objects)   %%%%%%%%%%
            obj = fromDom(obj, varargin{1}, varargin{2});

          elseif isa(varargin{1}, 'ltpda_uoh') && isa(varargin{2}, 'plist')
            %%%%%%%%%%%   timespan(<ltpda_uoh>-object, plist-object)   %%%%%%%%%%
            % always recreate from plist

            % If we are trying to load from file, and the file exists, do
            % that. Otherwise, copy the input object.
            if varargin{2}.isparam('filename')
              if exist(fullfile('.', find(varargin{2}, 'filename')), 'file')==2
                obj = timespan(varargin{2});
              else
                obj = timespan(varargin{1});
              end
            else
              obj = timespan(varargin{2});
            end

          else
            error ('  ### Unknown constructor with two inputs.');
          end

        case 3
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%   three input   %%%%%%%%%%%%%%%%%%%%%%%%%%
          %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

          if  (ischar(varargin{1}) || isnumeric(varargin{1}) || isa(varargin{1}, 'time')) && ...
              (ischar(varargin{2}) || isnumeric(varargin{2}) || isa(varargin{2}, 'time')) && ...
              ischar(varargin{3})
            %%%%%%%%%%  obj = timespan('14:00:00', '14:00:05', 'HH:MM:SS')  %%%%%%%%%%
            %%%%%%%%%%  obj = timespan(  200000  ,   300000  , 'HH:MM:SS')  %%%%%%%%%%
            %%%%%%%%%%  obj = timespan(time(2000), time(3000), 'HH:MM:SS')  %%%%%%%%%%
            %%%%%%%%%%  obj = timespan('00:01:00',   300000  , 'HH:MM:SS')  %%%%%%%%%%
            utils.helper.msg(msg.OPROC1, 'constructing from start/end and timeformat');
            pl = plist('STARTT', varargin{1}, 'ENDT', varargin{2}, 'timeformat', varargin{3});
            obj = obj.fromTimespanDef(pl);

          else
            error ('  ### Unknown constructor with three inputs.');
          end

        otherwise
          [tss, dummy, rest] = utils.helper.collect_objects(args, 'timespan');

          %%% Do we have a list of TIMESPANs as input
          if ~isempty(tss) && isempty(rest)
            obj = timespan(tss);
          else
            error('### Unknown number of arguments.');
          end
      end

      % Consistency check
      for ll = 1:numel(obj)
        if obj(ll).startT.utc_epoch_milli > obj(ll).endT.utc_epoch_milli
          error('### The start time is larger than the end time.');
        end
      end

    end % End constructor

  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                             Methods (public)                              %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  methods
    varargout = copy(varargin)
    varargout = setStartT(varargin)
    varargout = setEndT(varargin)
    varargout = double(varargin)
  end

  methods (Hidden = true)
    varargout = attachToDom(varargin)
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                             Methods (protected)                           %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  methods (Access = protected)
    varargout = fromStruct(varargin)
    varargout = fromDom(varargin)
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                           Methods (private)                               %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  methods (Access = private)
    obj = fromTimespanDef(obj, pli)
    str = computeInterval(obj)
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                            Methods (static)                               %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  methods (Static)

    function mdls = getBuiltInModels(varargin)
      mdls = ltpda_uo.getBuiltInModels('timespan');
    end

    function out = VEROUT()
      out = '$Id: timespan.m,v 1.89 2011/08/22 05:56:30 hewitson Exp $';
    end

    function ii = getInfo(varargin)
      ii = utils.helper.generic_getInfo(varargin{:}, 'timespan');
    end

    function out = SETS()
      out = [SETS@ltpda_uoh, {'From Timespan Definition'}];
    end

    
    function plout = getDefaultPlist(set)
      persistent pl;
      persistent lastset;
      if exist('pl', 'var')==0 || isempty(pl) || ~strcmp(lastset, set)
        pl = timespan.buildplist(set);
        lastset = set;
      end
      plout = pl;
    end

    function out = buildplist(set)

      if ~utils.helper.ismember(lower(timespan.SETS), lower(set))
        error('### Unknown set [%s]', set);
      end

      out = plist();
      out = timespan.addGlobalKeys(out);
      out = buildplist@ltpda_uoh(out, set);

      switch lower(set)
        case 'from timespan definition'

          p = param({'startT','The starting time.'}, paramValue.EMPTY_STRING);
          out.append(p);

          p = param({'endT','The ending time.'}, paramValue.EMPTY_STRING);
          out.append(p);

          p = param({'timezone','Timezone.'}, paramValue.TIMEZONE);
          out.append(p);

          p = param({'timeformat','Time format.'}, paramValue.STRING_VALUE(''));
          out.append(p);
      end
    end % function out = getDefaultPlist(varargin)

    function obj = initObjectWithSize(n,m)
      obj = timespan.newarray([n m]);
    end

  end % End static methods

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                         Methods (static, private)                         %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  methods (Static, Access=private)
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                         Methods (static, hidden)                          %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  methods (Static = true, Hidden = true)
    varargout = loadobj(varargin)
    varargout = update_struct(varargin);
  end

end % End classdef

