function initialize(h)

%% Builds the Data Selection GUI

import javax.swing.*; 
import java.awt.*;

%% Selection rules
h.Rules = tsguis.exclusion;

%% Main figure
h.Figure = figure('Units','Characters','Position',[104 31.2989 110 39],'Toolbar','None',...
    'Menubar','None','NumberTitle','off','Name','Select Data Using Rules',...
    'Visible','off','closeRequestFcn',@(es,ed) set(h,'Visible','off'),...
    'HandleVisibility','callback');

%% Build buttons
BTNok = uicontrol('String','OK','Parent',h.Figure,'Units','Characters','Position',...
    [62.6 0.6152 13.2 1.7687],'Callback',{@localOK h});
BTNapply = uicontrol('String','Apply','Parent',h.Figure,'Units','Characters','Position',...
    [78.2 0.6152 13.2 1.7687],'callback',{@localApply h});
BTNcancel = uicontrol('String','Cancel','Parent',h.Figure,'Units','Characters','Position',...
    [93.6 0.6152 13.2 1.7687],'Callback',@(es,ed) set(h,'Visible','off'));

%% Build rule combination panel
PNLCombine = uipanel('Parent',h.Figure,'Units','Characters','Position',[0 2.9222 109 12.1508],...
    'Title','Combine Selection Rules');
[h.Handles.combineTable, combineTablePanel] = tsuitable(h.Figure,repmat({''},[4 2]), ...
    {'Selection Criterion','Logical Combination'});
awtinvoke(h.Handles.combineTable.getTable,'setAutoResizeMode(I)',...
    JTable.AUTO_RESIZE_ALL_COLUMNS);

h.Handles.combineTable.setComboBoxEditor({{'and','or'}},2);
set(h.Handles.combineTable,'DataChangedCallback',{@localCombineChanged h});
tsCustomizeUitable(h.Handles.combineTable)
h.Handles.combineTable.setColumnWidth(205);
set(combineTablePanel,'Units','Pixels','Parent',PNLCombine,'Position', ...
    hgconvertunits(ancestor(PNLCombine,'figure'),[2 2.769 102 7.4593],'Characters',...
    'Pixels',PNLCombine));
h.Handles.combineTable.setRowHeight(17);
h.Handles.LBLDesription = uicontrol('Style','Text','Parent',PNLCombine,...
    'Units','Characters','Position',[2 0.5 96 1.5],'HorizontalAlignment','Left');

%% Add a listener to the selection rules to update the logic table
L = handle.listener(h.Rules,'rulechange',...
    {@localRuleChange h.Handles.combineTable h});
L.CallbackTarget = h.Rules;
h.addlisteners(L);

%% Build selection criteria panel
PNLSelection = uipanel('Parent',h.Figure,'Units','Characters','Position',[0 15.1499 99 10.9967],...
    'Title','Define Selection Rules');
JAVAselectPanel = localBuildJavaSelection(h);
wrapPanel = JPanel(GridLayout(1,1)); % work around for G232843
wrapPanel.add(JAVAselectPanel);
wrapPanel.setOpaque(true); 
[junk, jPNLselection] = javacomponent(wrapPanel);
set(jPNLselection,'Parent',PNLSelection,'Units','Pixels','Position', ...
    hgconvertunits(ancestor(PNLSelection,'figure'),[2 0.769 105 8.6897],'Characters',...
    'Pixels',PNLSelection))

%% Top Time series selection panel
TSPanel = uipanel('Parent',h.Figure);
set(TSPanel,'Units','Characters','Position',[0 26.4542 109 10.8429],...
    'Title','Select the Time Plot and Time Series');
h.Handles.LBLselts = uicontrol('style','text','String','Select the time plot','Units',...
    'Characters','Parent',TSPanel, 'Position',[3 7.6131 19.2 1.1535]);
h.Handles.COMBOselectView = uicontrol('style','popupmenu','String',{'  '},'Units',...
    'Characters','Parent',TSPanel,'Position',[26 7.4593 69.6 1.5380],'Callback', ...
    {@localSwitchView h},'BackgroundColor',[1 1 1]);
[h.Handles.tsTable, tsTablePanel] = tsuitable(cell(0,3), ...
    {'Select from (y/n)?','Displayed Timeseries','Selected column(s)'});
tsCustomizeUitable(h.Handles.tsTable,2)
h.Handles.tsTable.setCheckBoxEditor(1);
awtinvoke(h.Handles.tsTable.getTable,'setAutoResizeMode(I)',JTable.AUTO_RESIZE_ALL_COLUMNS)
set(tsTablePanel,'Parent',TSPanel,'Units','Pixels','Position',...
    hgconvertunits(ancestor(TSPanel,'figure'),[2.6 0.769 102 5.7675],'Characters',...
    'Pixels',TSPanel));

%% Make th figure background color match the uipanel color
set(h.Figure,'Color',get(TSPanel,'BackGroundColor'))

%% Install listeners
h.generic_listeners

%% Refresh rule table
localSendRuleChange(h.rules,true(4,1))

h.Handles.combineTable.setRowHeight(22);

function PNLSelection =  localBuildJavaSelection(h)

%% Builds the java tabbed panel which defines selection rules

import com.mathworks.mwswing.*;
import com.mathworks.page.utils.VertFlowLayout;
import java.awt.*;
import javax.swing.*;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Build Bounds Panel
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Build upper left time panel
PNLTimeBoundsTop = MJPanel;
LBLSelectTimeTop = MJLabel('Select time:');
ComponentSize = LBLSelectTimeTop.getPreferredSize;
COMBOOrderingTimeTop = MJComboBox;
localPopulateOrderCombo(COMBOOrderingTimeTop,2);
TXTTimeTop = MJTextField(14);
BTNTimeTop = MJButton('...');
set(handle(BTNTimeTop,'callbackproperties'),'ActionPerformedCallback',...
    {@localCalendar h TXTTimeTop})
BTNTimeTop.setPreferredSize(Dimension(ComponentSize.getHeight, ...
    ComponentSize.getHeight));
PNLTimeBoundsTop.add(LBLSelectTimeTop);
PNLTimeBoundsTop.add(COMBOOrderingTimeTop);
PNLTimeBoundsTop.add(TXTTimeTop);
PNLTimeBoundsTop.add(BTNTimeTop);

%% Build lower left time panel
PNLTimeBoundsBottom = MJPanel;
LBLSelectTimeBottom = MJLabel('and');
LBLSelectTimeBottom.setPreferredSize(ComponentSize);
COMBOOrderingTimeBottom = MJComboBox;
localPopulateOrderCombo(COMBOOrderingTimeBottom,1);
TXTTimeBottom = MJTextField(14);
BTNTimeBottom = MJButton('...');
set(handle(BTNTimeBottom,'callbackproperties'),'ActionPerformedCallback',...
    {@localCalendar h TXTTimeBottom})
BTNTimeBottom.setPreferredSize(Dimension(ComponentSize.getHeight, ...
    ComponentSize.getHeight));
PNLTimeBoundsBottom.add(LBLSelectTimeBottom);
PNLTimeBoundsBottom.add(COMBOOrderingTimeBottom);
PNLTimeBoundsBottom.add(TXTTimeBottom);
PNLTimeBoundsBottom.add(BTNTimeBottom);

%% Build time panel
PNLTime = MJPanel(VertFlowLayout(VertFlowLayout.TOP));
PNLTime.add(PNLTimeBoundsTop);
PNLTime.add(PNLTimeBoundsBottom);

%% Build upper right data panel
PNLDataBoundsTop = MJPanel;
LBLSelectDataTop = MJLabel('and select data:');
COMBOOrderingDataTop = MJComboBox;
localPopulateOrderCombo(COMBOOrderingDataTop,2);
TXTDataTop = MJTextField(7);
PNLDataBoundsTop.add(LBLSelectDataTop);
PNLDataBoundsTop.add(COMBOOrderingDataTop);
PNLDataBoundsTop.add(TXTDataTop);

%% Build lower right data panel
PNLDataBoundsBottom = MJPanel;
LBLSelectDataBottom = MJLabel('and');
LBLSelectDataBottom.setPreferredSize(LBLSelectDataTop.getPreferredSize);
COMBOOrderingDataBottom = MJComboBox;
localPopulateOrderCombo(COMBOOrderingDataBottom,1);
TXTDataBottom = MJTextField(7);
PNLDataBoundsBottom.add(LBLSelectDataBottom);
PNLDataBoundsBottom.add(COMBOOrderingDataBottom);
PNLDataBoundsBottom.add(TXTDataBottom);

%% Build data panel
PNLData = MJPanel(VertFlowLayout(VertFlowLayout.TOP,5,5));
PNLData.add(PNLDataBoundsTop);
PNLData.add(PNLDataBoundsBottom);

%% Build bounds panel
%PNLBounds = MJPanel(GridLayout(1,2));
PNLBounds = MJPanel(FlowLayout(FlowLayout.LEFT,0,0));
PNLBounds.add(PNLTime);
PNLBounds.add(PNLData);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Build Outlier Panel
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

PNLOutliers = MJPanel(FlowLayout(FlowLayout.LEFT));
LBLWindow = MJLabel('Window length (samples)');
TXTWindow = MJTextField(5);
LBLConf = MJLabel('Confidence limit (%)');
TXTConf = MJTextField(5);
PNLOutliers.add(LBLWindow);
PNLOutliers.add(TXTWindow);
PNLOutliers.add(LBLConf);
PNLOutliers.add(TXTConf);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Build Expression Panel
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

PNLExpression = MJPanel(FlowLayout(FlowLayout.LEFT));
LBLExp = MJLabel('MATLAB expression using x to represent data');
TXTExp = MJTextField(20);
PNLExpression.add(LBLExp);
PNLExpression.add(TXTExp);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Build Flatline Panel
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

PNLFlatline = MJPanel(FlowLayout(FlowLayout.LEFT));
LBLMaxLen = MJLabel('Minimum length in samples');
TXTMaxLen = MJTextField(15);
PNLFlatline.add(LBLMaxLen);
PNLFlatline.add(TXTMaxLen);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Build Data Status Panel
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% This panel will only be enabled if the selected time series have common
%% data status descriptions otherwise a help message will be displayed
% PNLDataStaus = MJPanel(FlowLayout(FlowLayout.LEFT));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Build Data Selection Panel
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

PNLSelection = MJTabbedPane;
PNLBounds.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
PNLSelection.addTab('Bounds',PNLBounds);
PNLOutliers.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
PNLSelection.addTab('Outlier Detection',PNLOutliers);
PNLExpression.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
PNLSelection.addTab('MATLAB Expression',PNLExpression);
PNLFlatline.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
PNLSelection.addTab('Flatline Values',PNLFlatline);
% PNLDataStaus.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
% PNLSelection.addTab('Data Status',PNLDataStaus);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Define Callbacks
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Add time panel callbacks
timeChangeCallback = {@localBound h TXTTimeTop TXTTimeBottom ...
    COMBOOrderingTimeTop COMBOOrderingTimeBottom 'time'};
set(handle(TXTTimeTop,'callbackproperties'),'ActionPerformedCallback',...
    timeChangeCallback,'FocusLostCallback',timeChangeCallback)
set(handle(TXTTimeBottom,'callbackproperties'),'ActionPerformedCallback',...
    timeChangeCallback,'FocusLostCallback',timeChangeCallback)
set(handle(COMBOOrderingTimeTop,'callbackproperties'),'ActionPerformedCallback',...
    timeChangeCallback,'FocusLostCallback',timeChangeCallback)
set(handle(COMBOOrderingTimeBottom,'callbackproperties'),'ActionPerformedCallback',...
    timeChangeCallback,'FocusLostCallback',timeChangeCallback)
dataChangeCallback = {@localBound h TXTDataTop TXTDataBottom ...
    COMBOOrderingDataTop COMBOOrderingDataBottom 'data'};
set(handle(TXTDataTop,'callbackproperties'),'ActionPerformedCallback',...
    dataChangeCallback,'FocusLostCallback',dataChangeCallback)
set(handle(TXTDataBottom,'callbackproperties'),'ActionPerformedCallback',...
    dataChangeCallback,'FocusLostCallback',dataChangeCallback)
set(handle(COMBOOrderingDataTop,'callbackproperties'),'ActionPerformedCallback',...
    dataChangeCallback,'FocusLostCallback',dataChangeCallback)
set(handle(COMBOOrderingDataBottom,'callbackproperties'),'ActionPerformedCallback',...
    dataChangeCallback,'FocusLostCallback',dataChangeCallback)

%% Add outlier callbacks
outlierCallback = {@localOutlier h.rules TXTWindow TXTConf};
set(handle(TXTWindow,'callbackproperties'),'ActionPerformedCallback',...
    outlierCallback,'FocusLostCallback',outlierCallback)
set(handle(TXTConf,'callbackproperties'),'ActionPerformedCallback',...
    outlierCallback,'FocusLostCallback',outlierCallback)

%% Add MATLAB expression callbacks
expressioncallback = {@localExpression h.rules TXTExp}; 
set(handle(TXTExp,'callbackproperties'),'ActionPerformedCallback',...
    expressioncallback,'FocusLostCallback',expressioncallback)

%% Add flatline callbacks
flatlinecallback = {@localFlatline h.rules TXTMaxLen};
set(handle(TXTMaxLen,'callbackproperties'),'ActionPerformedCallback',...
    flatlinecallback,'FocusLostCallback',flatlinecallback)

function localPopulateOrderCombo(thisCombo,selectedItem)

classArray = javaArray('java.lang.Class',1);
classArray(1) = java.lang.Class.forName('java.lang.Object');
meth = thisCombo.getClass.getMethod('addItem',classArray);
awtinvoke(thisCombo,meth,java.lang.String('<='));
awtinvoke(thisCombo,meth,java.lang.String('>='));
awtinvoke(thisCombo,meth,java.lang.String('<'));
awtinvoke(thisCombo,meth,java.lang.String('>'));
classArray(1) = java.lang.Class.forName('java.lang.Integer');

awtinvoke(thisCombo,'setSelectedIndex(I)',selectedItem-1);

function localSwitchView(eventSrc, eventData, h)

%% View combo callback which changes the viewNode
ind = get(eventSrc,'Value');
views = get(eventSrc,'Userdata');
h.ViewNode = views(ind);

function emptyset = localApply(eventSrc, eventData, h)

recorder = tsguis.recorder;

%% Find the selected time series and columm after finishing editing
celleditor = h.Handles.tsTable.getTable.getCellEditor;
if ~isempty(celleditor)
    awtinvoke(celleditor,'stopCellEditing');
    drawnow
end

%% Find the time series to be used for selection
tsTableData = cell(h.Handles.tsTable.Data);
tsList = {};
selectedCols = {};
for k=1:size(tsTableData,1)
    if tsTableData{k,1}
        thists = h.Viewnode.Plot.getTimeSeries(tsTableData{k,2});
        thesecols = eval(tsTableData{k,3},'[]');
        if ~isempty(thists) && ~isempty(thesecols) && all(thesecols>=1) && ...
                all(thesecols<=size(thists.Data,2))
            tsList = [tsList(:); {thists}];
            selectedCols = [selectedCols; {thesecols}];
        else
            errordlg(sprintf('Invalid entry for time series %s.',thists.Name),...
                'Time Series Tool','modal')
            return
        end
    end
end

%% Move the current plot into the foreground. This must be done to prevent
%% HG from incorrectly setting the toolbar mode of the Selection dialog
%% figure in response to setting the Plot figure into selction mode
figure(ancestor(h.ViewNode.Plot.AxesGrid.Parent,'figure'))

%% Exit normalizition mode so that the selected curves will display
%% correctly
h.Viewnode.Plot.axesgrid.YNormalization = 'off';

%% For each selected time series and columns make the selection
h.ViewNode.Plot.setselectmode('DataSelect');
emptyset = true;
for k=1:length(tsList)
    %% Find selected points
    s = size(tsList{k}.Data);
    I = false(s);
    I(:,selectedCols{k}) = true;
    [ind, History] = h.Rules.feval(tsList{k});
    I = I & ind;
    if strcmp(recorder.Recording,'on')
         h.ViewNode.Plot.SelectionStruct.History = [h.ViewNode.Plot.SelectionStruct.History;...
            History;... 
           {'%% Restricting rule selection to specified columns'};...
           {[ 'I' tsList{k}.Name ' = false([' num2str(s) ']);' ]};...
           {[ 'I' tsList{k}.Name '(:,[' num2str(selectedCols{k}) ']) = true;' ]};...
           {'%% Applying combined selection rules'};...
           {[ 'I' tsList{k}.Name '= I' tsList{k}.Name ' & idx;' ]}];

    end  
    if any(I(:))
        h.ViewNode.Plot.select(tsList{k},I);
        emptyset = false;
    end
end
 
%% Warn about empty set
if emptyset
    warndlg('The combination of the selection rules identifies an empty set (no selection).',...
        'Time Series Tool')
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Panel callbacks
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function localBound(eventSrc, eventData, h, TXTTop, TXTBottom, ...
    COMBOOrderingTop, COMBOOrderingBottom, type)

%% Time/Data bounds change callback - update rules object

%% Get ordering combo values
combVal{1} = COMBOOrderingTop.getSelectedItem;
combVal{2} = COMBOOrderingBottom.getSelectedItem;

%% Get bounds
if strcmp(type,'time') && ~isempty(h.ViewNode.Plot) && ...
        strcmp(h.ViewNode.Plot.Absolutetime,'on')
     topdate = char(TXTTop.getText);
     bottomdate = char(TXTBottom.getText);
     if ~isempty(topdate)
         try
             data{1} = tsunitconv(h.ViewNode.Plot.TimeUnits,'days')*...
                  (datenum(topdate)-datenum(h.ViewNode.Plot.StartDate));
         catch
             errordlg('Time bounds must be valid datastr','Time Series Tools','modal')
             TXTTop.setText(h.ViewNode.Plot.StartDate);
             return
         end
     else
         data{1} = [];
     end
     if ~isempty(bottomdate)
         try
             data{2} = tsunitconv(h.ViewNode.Plot.TimeUnits,'days')*...
                 (datenum(bottomdate)-datenum(h.ViewNode.Plot.StartDate));
         catch
             errordlg('Time bounds must be valid datastr','Time Series Tools','modal')
             TXTBottom.setText(h.ViewNode.Plot.StartDate);
             return
         end
     else
         data{2} = [];
     end
else    
     toptime = char(TXTTop.getText);
     bottomtime = char(TXTBottom.getText);
     if ~isempty(toptime)
         data{1} = eval(toptime,'[]');
         if isempty(data{1})
             TXTTop.setText('');
         end
     else
         data{1} = [];
     end
     if ~isempty(bottomtime)
         data{2} = eval(bottomtime,'[]');
         if isempty(data{2})
             TXTBottom.setText('');
         end
     else
         data{2} = [];
     end
end

%% Initialize
high = inf;
low = -inf;
highstrict = 'off';
lowstrict = 'off';

%% Update the "exclusion" object to reflect the bounds panel
for k=1:2
    switch combVal{k}
       case '<'
          if ~isempty(data{k}) && data{k}>=low
             low = data{k};
             lowstrict = 'on';   
          end
       case '<=' 
          if ~isempty(data{k}) && data{k}>=low
             if data{k}<low
                lowstrict = 'off';
             end
             low = data{k};
          end
       case '>'
          if ~isempty(data{k}) && data{k}<=high
             high = data{k}
             highstrict = 'on';
          end
       case '>=' 
          if ~isempty(data{k}) && data{k}<=high
             if data{k}>high
                highstrict = 'off';
             end
             high = data{k};
          end
    end
end

%% Write results to "exclusion" obj
if strcmp(type,'time')
    set(h.Rules,'Xlow',low,'Xhigh',high,'Xlowstrict',lowstrict,'Xhighstrict', ...
        highstrict,'Xunits',h.ViewNode.Plot.TimeUnits);
else
    set(h.Rules,'Ylow',low,'Yhigh',high,'Ylowstrict',lowstrict,'Yhighstrict',...
        highstrict);
end

%% Send a rule change to update the logic table 
localSendRuleChange(h.Rules,[true;false;false;false])

function localOutlier(eventSrc,eventData,h,TXTWindow,TXTConf)

%% Outliers change callback - update rules object
winlen = eval(char(TXTWindow.getText),'[]');
conf = eval(char(TXTConf.getText),'[]');
set(h,'Outlierwindow',winlen,'Outlierconf',conf);

%% Send a rule change to update the logic table 
localSendRuleChange(h,[false;true;false;false])

function localCombineChanged(eventSrc,eventData,h)

%% Rule combination table callback

%% Find active rules and their order
combineTableData = localProcessTable(h,cell(h.Handles.combineTable.Data));

%% Write modifed data back
h.Handles.combineTable.setmanual(true);
h.Handles.combineTable.setData(combineTableData);
drawnow
h.Handles.combineTable.setlocked(false);
h.Handles.combineTable.setmanual(false);

function localOK(eventSrc, eventData, h)

%% OK button callback
emptyset = localApply([],[],h);
if ~emptyset
    h.Visible = 'off';
end

function localRuleChange(es,ed,combineTable,h)

%% Callback to a rulechange event to update the logic table
activeRules = h.rules.isActive;
selectedRules = find(ed.SelectedRules);
tableData = cell(combineTable.getData);
ruleNames = {'Bounds';'Outlier Detection';'MATLAB Expression';...
    'Flatline Values'};

%% Loop through each row 
for k=1:length(selectedRules)
    % If the active rule is not in the table then add it
    if activeRules(selectedRules(k)) && ...
            ~any(strcmp(tableData(:,1),ruleNames{selectedRules(k)}))
        ind = find(cellfun('isempty',tableData(:,1)));
        tableData(ind(1),:) = {ruleNames{selectedRules(k)},'or'};
    % If the inactive rule is in the table, remove it
    elseif ~activeRules(selectedRules(k)) && ...
            any(strcmp(tableData(:,1),ruleNames{selectedRules(k)}))
        ind = find(strcmp(tableData(:,1),ruleNames{selectedRules(k)}));
        tableData(ind,:) = [];
        tableData = [tableData; repmat({'',''},[length(ind),1])];
    end
end

% The table combo should only show active rules
if isempty(ruleNames(activeRules))
    combineTable.setComboBoxEditor({{''}},1);
else
    combineTable.setComboBoxEditor({[ruleNames(activeRules);{''}]},1);
end
%% Write modifed data back rmoving the last logical op
combineTable.setData(localProcessTable(h,tableData));

function localFlatline(es,ed,h,TXTMaxLen)

%% Length must be >1, int,scalar
flatlinelen = eval(char(getText(TXTMaxLen)),'[]');
if isempty(flatlinelen) || ~isscalar(flatlinelen) || ~isfinite(flatlinelen) || ...
        isnan(flatlinelen) || flatlinelen<2 || flatlinelen~=floor(flatlinelen)
    errordlg('Length must be a finite integer >1,','Time Series Tools','modal')
    TXTMaxLen.setText('');
    return
end

set(h,'Flatlinelength',eval(char(getText(TXTMaxLen)),'[]'))
localSendRuleChange(h,[false;false;false;true])

function localExpression(es,ed,h,TXTExp)

%% Callback for MATLAB expression edit box

%% Evauate expression with x =1 to check that it is valid and returns a
%% logical
x = 1;
outchk = eval(char(TXTExp.getText),'[]');

%% If valid the process rule changle, else reset
if ~isempty(outchk) && islogical(outchk)    
    set(h,'Mexpression',char(TXTExp.getText))
    localSendRuleChange(h,[false;false;true;false])
else
    errordlg('Expression must evaluate to a logical array,','Time Series Tools','modal')
    TXTExp.setText('');
end

function localSendRuleChange(rules,selected)

ed = handle.EventData(rules,'rulechange');
schema.prop(ed,'SelectedRules','MATLAB array');
ed.SelectedRules = selected;
rules.send('rulechange',ed);

function localCalendar(es,ed,h,TXTTime)

%% Validation
if isempty(h.ViewNode.Plot)
    return
end
if strcmp(h.ViewNode.Plot.Absolutetime,'off')
    errordlg('The calendar can only be used for plots with absolute time vectors',...
        'Time Series Tools','modal')
    return
end

if isempty(h.Calendar)
    h.Calendar = tsguis.calendar;
end

%% Parent the calendar to the current @selectrules
h.Calendar.Updatefcn = ...
    {@localCalendarCallback TXTTime h.Calendar};
h.Calendar.Parent = h;

%% Add calendar listeners (including the one to this @selectrules being
%% destroyed)
h.Calendar.generic_listeners

%% Open the calendar
h.Calendar.open

function localCalendarCallback(TXTTime,cal)

setText(TXTTime,datestr(cal.DateNum));
%% Invoke the callback
callback  = get(handle(TXTTime,'callbackproperties'),'ActionPerformedCallback');
feval(callback{1},[],[],callback{2:end});



function dataOut = localProcessTable(h,combineTableData)

%% Check for no duplication of rules
I1 = find(~cellfun('isempty',combineTableData(:,1)));
[urules,I2] = unique(combineTableData(I1,1));
if length(I2)<length(I1)
    combineTableData{I1(setdiff(1:length(I1),I2)),1} = '';
    combineTableData{I1(setdiff(1:length(I1),I2)),2} = '';
end
    
%% Remove empty rows
I = ~cellfun('isempty',combineTableData(:,1));
combineTableData = combineTableData([find(I);find(~I)],:);
 
%% Parse the second column. Replace blanks by 'and' 
ind = find(~cellfun('isempty',combineTableData(:,1)));
for k=1:length(ind)
    if ~isempty(combineTableData{ind(k),1}) && isempty(combineTableData{ind(k),2})
        combineTableData{ind(k),2} = 'and';
    end
end    
 
set(h.Rules,'BoundsPosition',0,'OutliersPosition',0,'ExpressionPosition',0,...
    'FlatlinePosition',0)
for row=1:size(combineTableData,1)
    if ~isempty(combineTableData{row,1}) % switch won't accept []
        switch combineTableData{row,1}
            case 'Bounds'
                set(h.Rules,'BoundsPosition',row,'BoundsLogicalOp', ...
                    combineTableData{row,2}) 
            case  'Outlier Detection'
                set(h.Rules,'OutliersPosition',row,'OutliersLogicalOp', ...
                    combineTableData{row,2})
            case 'MATLAB Expression'
                set(h.Rules,'ExpressionPosition',row,'ExpressionLogicalOp', ...
                    combineTableData{row,2})            
            case 'Flatline Values'
                set(h.Rules,'FlatlinePosition',row,'FlatlineLogicalOp', ...
                    combineTableData{row,2})              
            case 'Data Status'
                %h.Rules.FlatlinesActive = 'on';
        end
    else
        combineTableData{row,2} = '';
    end
end
 
%% Make sure the last non-empty row has logical operation is blank
if ~isempty(ind)
    combineTableData{ind(end),2} = '';
end
 
%% Update description label
descstr = '';
for k=1:size(combineTableData,1)
    if ~isempty(combineTableData{k,1})
         descstr = [descstr, ' ', combineTableData{k,1} ' '  combineTableData{k,2}];
    end
end
set(h.Handles.LBLDesription,'String',descstr);

dataOut = combineTableData;