function [tsout,ind] = tsxeval(expr,tslist)
%XEVAL Expression evaluation
%
%   Author(s): James G. Owen
%   Copyright 1986-2004 The MathWorks, Inc.
%   $Revision: 1.1.6.1 $ $Date: 2004/12/26 21:46:37 $

%% Sort the time series by length of name. This will allow the expression
%% parser to detect occurances of the longest time series name first so
%% that subsumed time series names are not articically detected
tsnames = cell(length(tslist),1);
for k=1:length(tslist)
    tsnames{k} = tslist{k}.Name;
end
[junk,I] = sort(-cellfun('length',tsnames));
tsnames = tsnames(I);
tslist = tslist(I);

% Create local variables with names defined by the time series object
% names and values defined by the @timeseries ordinate data
ind = [];
tmpexpr = expr;
for k=1:length(tsnames)
    pos = strfind(tmpexpr,tsnames{k});
    if ~isempty(pos);
       % Create a local variable containig
       data = tslist{k}.Data;
       eval(sprintf('%s = data;',tslist{k}.Name));
       ind = [ind;k];
       
       % Remove occurances of this time series name from the expression
       % so that time series who's names are subsumed by longer time series
       % names are not falsly detected within longer time series names
       I = [];
       for j=1:length(pos)
           I = [I, pos(j):pos(j)+length(tsnames{k})-1];
       end
       tmpexpr(I) = '';
    end
end

% Evaluate expression using time series data
result = eval(sprintf('%s;',expr));
if isempty(ind) || ...
        ~isequal(size(result,1),tslist{ind(1)}.TimeInfo.getlength) % Functional expression return result
    tsout = result;
    return
elseif isempty(result)
    error('Invalid expression')
end
tsoutdata = result;
% If we get here we have a time series operator expression which
% requires partially sinconized time vectors to generate an output time
% series


ts = tslist{ind(1)};
tsInfo = ts.TimeInfo;
tsoutvec = ts.Time;

% Check sizes match
for k=2:length(ind)
    if ~isequal(getGridSize(ts),getGridSize(tslist{ind(k)}))
        error('Time series have differing lengths')
    end
end

% Loop through each time vector and convert to the smallest units and
% the earliest start date (if any)
outprops = struct('ref',tsInfo.StartDate,'outformat',tsInfo.Format,'outunits',...
    tsInfo.Units);      
for k=2:length(ind)
   [tsoutvec,tsoutvec2,outprops] = ...
        timemerge(tsInfo,tslist{ind(k)}.timeInfo,tsoutvec,tslist{ind(k)}.time);
   set(tsInfo,'StartDate',outprops.ref,'Format',outprops.outformat,...
       'Units',outprops.outunits);
   % Relative time vectors - remove initial values
   if isempty(outprops.ref) 
       tsoutvec = tsoutvec-tsoutvec(1);
       tsoutvec2 = tsoutvec2-tsoutvec2(1);
   end
   % Check that the time vectors match
   intervalLen = ((tsoutvec(end)-tsoutvec(1))/length(tsoutvec));
   if norm(tsoutvec-tsoutvec2)/intervalLen>1e-6
      error('timeseries:xeval:badsizes', 'Time vectors do not match')
   end
end

% Create output time series
tsout = tsdata.timeseries(tsoutdata,tsoutvec);
set(tsout.timeInfo,'Startdate',outprops.ref,'Units', ...
      outprops.outunits,'Format',outprops.outformat);

