function syncts(h,varargin)

%% Syncs the timeseries object with the tsnode/Tstable 

%% TO DO: Use the start,end row and col info to optimize efficiency

%% Find the non-empty cells in the first column which correspond to
%% non-empty non-event rows
tableData = cell(h.Tstable.Table.Data);
I = ~cellfun('isempty',tableData(:,1)) & ...
    cellfun('isclass',tableData(:,2),'double');
if size(tableData,2)<=2 % Empty rows excluded
    I = I & ~cellfun('isempty',tableData(:,2:end));
else % Partially empty rows excluded
    I = I & ~any(cellfun('isempty',tableData(:,2:end))')'; 
end
    
%% Parse the time vector as either a vector of datastrs or a numeric vector
if all(cellfun('isclass',tableData(I,1),'char'))
    newTime = tableData(I,1);
elseif all(cellfun('isclass',tableData(I,1),'double'))
    newTime = cell2mat(tableData(I,1));
else
    error('tsnode:syncts:mixedtype',...
        'Invalid time vector specified in the table')
end

%% Compute the new ordinate data - any strings become NaN - if quality is
%% present is must be the last column
newQuality = [];
if isempty(h.Timeseries.Quality)
    newOrdData = tableData(I,2:end);
else
    newOrdData = tableData(I,2:end-1);
    newQuality = tsParseStatus(h,tableData(I,end));
end
Inumeric = cellfun('isclass',newOrdData,'double') & ...
    ~cellfun('isempty',newOrdData);
newOrdData(~Inumeric) = {NaN};
newOrdData = cell2mat(newOrdData);

%% Reset time,data,qual
try
    if ~isequal(newOrdData,h.Timeseries.Data) || ~isequal(newTime,h.Timeseries.Time) || ...
            ~isequal(newQuality,h.Timeseries.Quality)
             
        %% Create transaction
        T = tsguis.transaction;
        recorder = tsguis.recorder;
              
        if strcmp(recorder.Recording,'on')
            T.addbuffer('%% Table modification');
            % Data or Time vector have been modifed
            if length(newTime)==length(h.Timeseries.Time) 
                % Ordinate data has been modified
                if ~isequal(newOrdData,h.Timeseries.Data)
                    I = (newOrdData~=h.Timeseries.Data) & (~isnan(newOrdData) | ~isnan(h.Timeseries.Data));
                    [indx,indy] = ind2sub(size(I),find(I));
                    if ~isempty(indx) && ~isempty(indy)
                        T.addbuffer([h.Timeseries.Name '.Data(' num2str(indx(1)) ',' num2str(indy(1)) ...
                            ') = ' sprintf('%f',newOrdData(indx(1),indy(1))) ';'],h.Timeseries);
                    end
                % Time vector has been mofified
                elseif ~isequal(newTime,h.Timeseries.Time)
                    I = find(newTime~=h.Timeseries.Time);
                    [indx,indy] = ind2sub(size(I),find(I));
                    if ~isempty(indx) && ~isempty(indy)
                        T.addbuffer([h.Timeseries.Name '.Time(' num2str(I(1)) ...
                            ') = ' sprintf('%f',newTime(I(1))) ';'],h.Timeseries);
                    end  
                % Quality has been modified
                elseif ~isequal(newQuality,h.Timeseries.Quality)
                    if length(newQuality) == length(h.Timeseries.Quality) % qual changed
                       I = find(newQuality~=h.Timeseries.Quality);
                       [indx,indy] = ind2sub(size(I),find(I));
                       if ~isempty(indx) && ~isempty(indy)
                           T.addbuffer([h.Timeseries.Name '.Quality(' num2str(I(1)) ...
                                ') = ' sprintf('%f',newQuality(I(1))) ';'],h.Timeseries);
                       end   
                    elseif length(newQuality)==0 % qual vector removed
                       T.addbuffer([h.Timeseries.Name '.Quality = [];'],h.Timeseries);
                    elseif length(h.Timeseries.Quality)==0 % fresh constant quality vector
                       T.addbuffer([h.Timeseries.Name ...
                           '.Quality = ones(' num2str(h.Timeseries.Time) ',1)*' ...
                           num2str(newQuality(1)) ';'],h.Timeseries);
                    end   
                end
            % Row has been deleted
            elseif length(newTime)<length(h.Timeseries.Time) 
                [junk,I] = setdiff(h.Timeseries.Time,newTime);
                T.addbuffer([h.Timeseries.Name '.delsample(''index'',[' num2str(I(:)') ']);'],...
                    h.Timeseries);
            % Row has been added
            elseif length(h.Timeseries.Time)<length(newTime)
                [junk,I] = setdiff(newTime,h.Timeseries.Time);
                T.addbuffer([h.Timeseries.Name '.addsample(''Time'',' num2str(newTime(I(1))), ...
                    ',''Data'',[' num2str(newOrdData(I(1),:)) ']);'],h.Timeseries);
            end
        end
        
        % Update the time series
        h.Timeseries.init(newOrdData,newTime,newQuality);

        
        %% Store transaction
        T.commit;
        recorder.pushundo(T);
    end
catch
    errordlg(sprintf('Invalid table entry: %s',lasterr),'Time Series Tools','modal')
    h.Timeseries.send('datachange')
    return
end
%h.synctable




function qual = tsParseStatus(h, statuscell)

%% Utility function which converts a cell array or Data Status strings to
%% Data Status codes in the Quality property

%% Loop through each quality code and description and convert the
%% corresponding entries of statuscell to their codes
qual = nan(size(statuscell));
for k=1:length(h.Timeseries.QualityInfo.Code)
    I = strcmp(h.Timeseries.QualityInfo.Description{k},statuscell);
    qual(I) = h.Timeseries.QualityInfo.Code(k);
end

%% No NaNs should be left or one of the quality strings does not match
%% h.QualityInfo.Description. If this happens reset the quality and revert
%% the table
if any(isnan(qual))
    qual = h.Timeseries.Quality;
    h.synctable
end


