function Panel = getDialogSchema(this,manager)

import javax.swing.*;

%% Create the node panel and components
% note: '.12g' is used as the sprintf format to display values in the
% 'redifine unform time vector' panel.
Panel = localBuildPanel(manager.Figure,this,manager);

%% Build the table to represent time series data
this.synctable;

%% @tsnode listeners to keep the time series selection combo in sync with
%% the tree
L = [ handle.listener(this.up, 'ObjectChildAdded', ...
    {@localTSListUpdate this.Handles.COMBselecttimeseries manager}); ...
      handle.listener(this.up, 'ObjectChildRemoved', ...
    {@localTSListUpdate this.Handles.COMBselecttimeseries manager});...
      handle.listener(this.getRoot.Tsviewer.Viewsnode.getChildren, 'ObjectChildAdded', ...
    {@localViewListUpdate this.Handles.COMBexistview this.Handles.RADIOexist, ...
      this.Handles.RADIOnew, this.Handles.EDITnewview manager});...  
      handle.listener(this.getRoot.Tsviewer.Viewsnode.getChildren, 'ObjectChildRemoved', ...
    {@localViewListUpdate this.Handles.COMBexistview this.Handles.RADIOexist, ...
      this.Handles.RADIOnew, this.Handles.EDITnewview manager});... 
      handle.listener(this.getRoot.Tsviewer.Viewsnode.getChildren, 'viewcontentschange', ...
    {@localViewListUpdate this.Handles.COMBexistview, this.Handles.RADIOexist, ...
      this.Handles.RADIOnew,this.Handles.EDITnewview manager})];
this.addListeners(L);

%% Listener to show the current time vector
callbackfcn = {@localUpdateTimeVec this.Timeseries.TimeInfo ...
    this.Handles.TXTtimevector};
L = [handle.listener(this.Timeseries.TimeInfo,...
      this.Timeseries.TimeInfo.findprop('Start'),'PropertyPostSet', ...
      callbackfcn);
    handle.listener(this.Timeseries.TimeInfo,...
      this.Timeseries.TimeInfo.findprop('End'),'PropertyPostSet', ...
      callbackfcn);
    handle.listener(this.Timeseries.TimeInfo,...
      this.Timeseries.TimeInfo.findprop('Increment'),'PropertyPostSet', ...
      callbackfcn);
    handle.listener(this.Timeseries.TimeInfo,...
      this.Timeseries.TimeInfo.findprop('Units'),'PropertyPostSet', ...
      callbackfcn);
    handle.listener(this.Timeseries.TimeInfo,...
      this.Timeseries.TimeInfo.findprop('StartDate'),'PropertyPostSet', ...
      callbackfcn)];
      
this.addListeners(L);

% Exercise the listeners so that the combos are initially up-to-date 
localTSListUpdate(this.up,struct('Type','new','Node',this)...
    ,this.Handles.COMBselecttimeseries, manager);
localViewListUpdate(this.getRoot.Tsviewer.Viewsnode.down,[], ...
    this.Handles.COMBexistview, this.Handles.RADIOexist, this.Handles.RADIOnew,...
    this.Handles.EDITnewview, manager);
localUpdateTimeVec([],[],this.Timeseries.TimeInfo,this.Handles.TXTtimevector);

% Temporary listeners to update table visibility when the enclosing panel
% visibility is modified
h = handle(Panel);
this.addListeners(handle.listener(h,h.findprop('Visible'),'PropertyPostSet',...
    {@localSetVisible h this.Handles.CHKevents this.Handles.PNLevents}));

set(this.Handles.PNLdata,'Visible','on')
figure(double(manager.Figure))


function f = localBuildPanel(thisfig,h,manager)

%% Create and position the components on the panel
f = uipanel('Parent',thisfig,'Units','Characters','Visible','off');

%% Data split pane
h.Handles.PNLdata = uipanel('Parent',f,'Units','Characters','Title','Edit Data',...
    'ResizeFcn',{@localDataResize h},'Visible','off');

%% Top tsdata panel
h.Handles.PNLtstable = uipanel('Parent',h.Handles.PNLdata,'Units','Characters',...
    'BorderType','None');

TXTselecttimeseries = uicontrol('Style','text','Parent',f,'Units',...
    'Characters','String','Select time series');
h.Handles.COMBselecttimeseries = uicontrol('Style','popup','Parent',...
    f,'Units','Characters','String',{' '},'BackgroundColor',[1 1 1],'Callback',...
    {@localTsComboCallback h manager});
BTNattributes = uicontrol('Style', 'pushbutton','Parent',h.Handles.PNLtstable, ...
    'Units','Characters','String','Define attributes','Callback',...
    @(es,ed) attributesdlg(h));
h.Handles.CHKevents = uicontrol('Style','checkbox','Parent',h.Handles.PNLtstable, ...
    'Units','Characters','String','Show event definition table below',...
    'Value',true,'Callback',{@localShowEventTable h});
h.Handles.BTNaddrow = uicontrol('Style','pushbutton','Parent',h.Handles.PNLtstable, ...
    'Units','Characters','String',...
    'Add row','Callback',{@localAddRow h});
h.Handles.BTNdelrow = uicontrol('Style','pushbutton','Parent',h.Handles.PNLtstable, ...
    'Units','Characters','Interruptible','off',...
    'String','Delete row(s)','Callback',{@localDeleteRow h});

%% Events panel
h.Handles.PNLevents = uipanel('Parent',h.Handles.PNLdata,'Units','Characters',...
    'BorderType','None');
h.eventpnl(h.Handles.PNLevents);

%% Build the empty uitable
h.Tstable = tsguis.timetable;
h.Tstable.initialize(h.Handles.PNLtstable,h.PopupMenu)
PNLtable = h.Tstable.TablePanel;
set(h.Tstable.Table,'DataChangedCallback',{@localTableDataChanged h},'Visible',false);

%% Size table
tablePos =  hgconvertunits(ancestor(PNLtable,'figure'),...
             [5.4 5.6137 117.6 31.1445],...
            'Characters','Pixels',get(PNLtable,'Parent'));
set(PNLtable,'Visible','off','Parent',h.Handles.PNLtstable,'Position',tablePos)
set(h.Handles.PNLtstable, 'resizeFcn', ...
    {@localTablePnlResize BTNattributes h.Handles.BTNaddrow ...
    h.Handles.BTNdelrow h.Handles.CHKevents PNLtable});

%% Time vector panel
PNLtime = uipanel('Parent',f,'Units','Characters','Title','Redefine Uniform Time Vector');
BTNPanel = uibuttongroup('Parent',PNLtime,'Units','Characters',...
    'Position',[0.2 3.15 20 7],'BorderType','None','SelectionChangeFcn',...
    {@localAbsRelChange h});
h.Handles.RADIOrelTime = uicontrol('Style','Radiobutton','Parent',BTNPanel,...
     'HorizontalAlignment','Left','String','Relative','Units',...
     'Characters','Position',[3.8 3 39 1.538]);
h.Handles.RADIOabsTime = uicontrol('Style','Radiobutton','Parent',BTNPanel,...
     'HorizontalAlignment','Left','String','Absolute','Units','Characters',...
     'Position',[3.8 5.1523 39 1.538]); 
currentTimeVec = sprintf('%s\n%s','Current time vector: ',  h.History);
h.Handles.TXTtimevector = uicontrol('Style','text','Parent',PNLtime,'Units','Characters', ...
    'Position',[3 0.2076 70.6 2],'String',currentTimeVec , ...
    'HorizontalAlignment','left');
TXTstart = uicontrol('Style','text','Parent',PNLtime,'Units','Characters', ...
    'Position',[22.6 8.1514 9.8 1.3073],'String','Start time:','HorizontalAlignment',...
    'Left');
h.Handles.EDITstart = uicontrol('Style','edit','Parent',PNLtime,'Units','Characters',...
    'Position',[33.2 8 22.4 1.6149],'BackgroundColor',[1 1 1],'HorizontalAlignment',...
    'Left','String',sprintf('%.12g',h.Timeseries.TimeInfo.Start));
h.Handles.BTNstart = uicontrol('Style','pushbutton','Parent',PNLtime,'Units', ...
    'Characters','Position',[56.8 8.0745 4.4 1.6918],'String','...','Callback', ...
     {@localCalendar h 'start'});
TXTend = uicontrol('Style','text','Parent',PNLtime,'Units','Characters',...
    'Position',[22.6 5.9213 12 1.3073],'String','End time:','HorizontalAlignment','Left');
TXTformat = uicontrol('Style','text','Parent',PNLtime,'Units','Characters',...
    'Position',[22.6 3.6143 12 1.3073],'String','Format:','HorizontalAlignment','Left');
h.Handles.COMBformat = uicontrol('Style','popupmenu','Parent',PNLtime,'Units', ...
    'Characters','Position',[33.2 3.6912 22.4 1.6149],'Callback',{@localsetFormat h},'String',...
     tsgetDateFormat,'HorizontalAlignment','left','BackgroundColor',[1 1 1]);
h.Handles.EDITend = uicontrol('Style','edit','Parent',PNLtime,'Units','Characters', ...
    'Position',[33.2 5.8444 22.4 1.6149],'BackgroundColor',[1 1 1],'HorizontalAlignment',...
    'Left','String',sprintf('%.12g',h.Timeseries.TimeInfo.End));
h.Handles.BTNend = uicontrol('Style','pushbutton','Parent',PNLtime,'Units', ...
    'Characters','Position',[56.8 5.8444 4.4 1.6918],'String','...','Callback',...
    {@localCalendar h 'end'});
TXTinterval = uicontrol('Style','text','Parent',PNLtime,'Units', ...
    'Characters','Position',[67.6 7.6131 9.8 1.7687],'String','Interval:','HorizontalAlignment',...
    'Left');
h.Handles.EDITinterval = uicontrol('Style','edit','Parent',PNLtime,'Units',...
    'Characters','Position',[81.8 8  26.4 1.6149],'BackgroundColor',[1 1 1], ...
    'HorizontalAlignment','Left');
%% Set the default time interval as the average interval of the current
%% time vector, if the current time vector is non-uniformly sampled.
timeinterval = [];
if ~isnan(h.Timeseries.TimeInfo.Increment)
    timeinterval = h.Timeseries.TimeInfo.Increment;
elseif h.Timeseries.TimeInfo.Length>0
    timeinterval = (h.Timeseries.TimeInfo.End-h.Timeseries.TimeInfo.Start)/...
        max(h.Timeseries.TimeInfo.Length-1,1);
end

if ~isempty(timeinterval)
    set(h.Handles.EDITinterval,'String',sprintf('%.12g',timeinterval));
else
    set(h.Handles.EDITinterval,'String','1');
end
    
TXTtimeunit = uicontrol('Style','text','Parent',PNLtime,'Units',...
    'Characters','Position',[67.6 5.383 17.8 1.8456],'String','Time units:','HorizontalAlignment',...
    'Left');
h.Handles.COMBunits = uicontrol('Style','popupmenu','Parent',PNLtime,'Units', ...
    'Characters','Position',[81.6 5.6137 26.4 1.7687],'String', ...
     get(findtype('TimeUnits'),'Strings'),'HorizontalAlignment', ...
    'left','BackgroundColor',[1 1 1]);
% initialize the unit
I = find(strcmpi(h.Timeseries.TimeInfo.Units,get(h.Handles.COMBunits,'String')));
if ~isempty(I)
    set(h.Handles.COMBunits,'Value',I(1));
end 
BTNapply = uicontrol('Style','pushbutton','Parent',PNLtime,'Units', ...
    'Characters','Position',[97.4 0.8459 12.4 1.5380],'String','Apply','Callback',...
    {@localApply h});
if ~isempty(h.Timeseries.TimeInfo.Startdate)
    % ts object is using the absolute date format for the time vector
    set(h.Handles.RADIOrelTime,'Value',0);
    set(h.Handles.RADIOabsTime,'Value',1);
else
    % ts object is using the relative time format for the time vector
    set(h.Handles.RADIOrelTime,'Value',1);
    set(h.Handles.RADIOabsTime,'Value',0);
end
% initialize the time vector display
localAbsRelChange([],[],h)

%% View panel
h.Handles.BTNGRPdisp = uibuttongroup('Parent',f,'Units','Characters',...
    'Title','Display Time Series');
h.Handles.RADIOnew = uicontrol('Style','radiobutton','Parent',h.Handles.BTNGRPdisp,'Units', ...
    'Characters','Position',[1.8 3.1529 37 1],'String','Create new of type',...
    'Value',true);
viewtypenames = get(h.getRoot.tsViewer.ViewsNode.getChildren,{'Label'});
h.Handles.COMBViewType = uicontrol('Style','Popupmenu','String', ...
    viewtypenames,'Value',find(strcmp('Time Plots',viewtypenames)),'Parent',...
    h.Handles.BTNGRPdisp,'Units','Characters',...
    'Position',[29.8 2.922 22 1.6149],'BackgroundColor',[1 1 1]);
LBLviewName = uicontrol('Style','Text','String','named','Units','Characters',...
    'Parent',h.Handles.BTNGRPdisp,'Position',[52.8 2.6915 7 1.6149],'HorizontalAlignment',...
    'Left');
h.Handles.RADIOexist = uicontrol('Style','radiobutton','Parent',h.Handles.BTNGRPdisp,'Units', ...
    'Characters','Position',[1.8 1 37 1],'String','Add to existing view');
h.Handles.EDITnewview = uicontrol('Style','edit','Parent',h.Handles.BTNGRPdisp,'Units',...
    'Characters','Position',[61.8 2.9222 29.6 1.6149],'String','Default view1', ...
    'HorizontalAlignment','left','BackgroundColor',[1 1 1]);
h.Handles.COMBexistview = uicontrol('Style','popup','Parent',h.Handles.BTNGRPdisp,'Units', ...
    'Characters','Position',[29.8 0.769 62.6 1.6918],'String',{'test'},'BackgroundColor',[1 1 1]);
h.Handles.BTNdisp = uicontrol('Style','pushbutton','Parent',h.Handles.BTNGRPdisp,'Units', ...
    'Characters','Position',[97.4 1 12.4 1.5380],'String','Display','callback',{@localView h});
set(f,'ResizeFcn',{@localFigResize h.Handles.PNLdata PNLtime TXTselecttimeseries ...
    h.Handles.COMBselecttimeseries PNLtable h.Handles.BTNGRPdisp});


function localFigResize(es,ed,PNLdata,PNLtime,TXTselecttimeseries,...
    COMBselecttimeseries,PNLtable,BTNGRPdisp)

%% Resize callback for tsnode panel
 
%% No-op if the panel is inivible or if there is no eventData passed with
%% the firing resize event
if strcmp(get(es,'Visible'),'off') && isempty(ed)
    return
end

%% Components and panels are repositioned relative to the main panel
mainpnlpos = hgconvertunits(ancestor(es,'figure'),get(es,'Position'),get(es,'Units'),...
    'Characters',get(es,'Parent'));

%% Set the time series selector size
set(TXTselecttimeseries,'Position',[1 max(1,mainpnlpos(4)-2.1456) 21.4 1]);
set(COMBselecttimeseries,'Position',[25 max(1,mainpnlpos(4)-2.607) max(1,mainpnlpos(3)-28) 1.6918]);

%% Set the time panel to have constant vertical position but to take up all
%% the space horizonatally
set(PNLtime,'Position',[1.8 7.69 max(1,mainpnlpos(3)-4.8) 11.4581]);

set(BTNGRPdisp,'Position',[1.8 1.2304 max(1,mainpnlpos(3)-4.8) 6]);

%% Set the table panel size to take up remaining space
set(PNLdata,'Position',[1.8 19.4557 max(1,mainpnlpos(3)-4.8) max(1,mainpnlpos(4)-22.5317)]);


function localSetVisible(es,ed,h,CHKevents,PNLevents)

children = h.find('-depth',inf,'-isa','uicontainer');
for k=1:length(children)
    % Do not turn the events panel visible if the events check box is off
    if children(k)~=PNLevents || get(CHKevents,'Value')>0.5  || ...
            (get(CHKevents,'Value')<0.5 && strcmp(get(h,'Visible'),'off'))
        set(children(k),'Visible',get(h,'Visible'));
    end        
end

function localTableDataChanged(eventSrc, eventData, this)

%% Callback for manual changes to data in the table

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Following rules apply for table data
%% Col 1: Is either all strings (for dates) or all doubles (for numerical
%% time)
%% Col 2:end-1: Is either all strings (for event rows) or all double (for
%% data rows)
%% Col end: May be combo boxes (for data status)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Find the data which was changed

startRow = eventData.getEvent.getFirstRow;
endRow = eventData.getEvent.getLastRow;
col = eventData.getEvent.getColumn;
if col<0 || startRow<0 
    return
end

%% Convert manually defined data from a string to a double under the 
%% following conditions:
%% 1. If it is ordinate data (not including the Data status column) and
%%    not on an event row
%% 2. If it is time data and the time vector is relative
%% Condition 2
tableData = cell(this.Tstable.Table.Data);
convertToDouble = (col==0 && ...
    ~this.Tstable.EventRow(startRow+1)) && ...
    isempty(this.Timeseries.TimeInfo.StartDate) && ...
    ~tsIsDateFormat(this.Timeseries.TimeInfo.Format);
%% Condition 1
convertToDouble = convertToDouble || (col>0 && ...
    (isempty(this.Timeseries.Quality) || col<size(tableData,2)-1) && ...
    ~this.Tstable.EventRow(startRow+1));

%% Refresh the table with the converted data type
if convertToDouble && ischar(tableData{startRow+1,col+1})
    % Table editor will insert a string "Infinity" to represent infs
    if strcmpi(tableData{startRow+1,col+1},'Infinity') || strcmpi(tableData{startRow+1,col+1},'inf')
         numVal = inf;
    elseif strcmpi(tableData{startRow+1,col+1},'-Infinity') || strcmpi(tableData{startRow+1,col+1},'-inf')
         numVal = -inf;
    else
         numVal = eval(tableData{startRow+1,col+1},'[]');
    end
    if col>0
        if ~isempty(numVal)
            if ~isreal(numVal)
                msgbox('Complex number will be converted to real',...
                    'Time Series Tools','modal')
            end
            if length(numVal)>1
                msgbox('Each table entry must be scalar valued. Converting to NaN.',...
                    'Time Series Tools','modal')
                numVal = NaN;
            end
            this.Tstable.Table.setDataAt(numVal,startRow,col)
        else
            this.Tstable.Table.setDataAt(NaN,startRow,col)
        end 
    elseif col==0
        if ~isempty(numVal) && isscalar(numVal) && isfinite(numVal) && ~isnan(numVal)
            this.Tstable.Table.setDataAt(numVal,startRow,col)
        else
            msgbox('Invalid time entry.',...
                    'Time Series Tools','modal') 
            %this.Tstable.Table.setDataAt(' ',startRow,col)
            this.synctable
            return
        end
    end
    drawnow % Table must be fully updated before calling syncts
elseif col==0 && ~isempty(this.Timeseries.TimeInfo.StartDate) % Abs time entry
    try     
        if tsIsDateFormat(this.Timeseries.TimeInfo.Format)
            dateStrVal = datestr(datenum(tableData{startRow+1,col+1}),...
                this.Timeseries.TimeInfo.Format);
            % Blank cell -> revert
            if isempty(dateStrVal)
                this.synctable
                return
            end
        else
            dateStrVal = datestr(datenum(tableData{startRow+1,col+1}),...
                'dd-mmm-yyyy HH:MM:SS');
        end
    catch
        errordlg('Invalid date/time string','Time Series Tools','modal')
        % Revert
        this.synctable
        return
    end
    this.Tstable.Table.setDataAt(dateStrVal,startRow,col)
    drawnow % Table must be fully updated before calling syncts
end

%% If the row is incomplete the @timeseries should not be updated
%% or the partially blank row will be overwritten
if any(cellfun('isempty',tableData(startRow+1,:)))
    return
end

%% Update the time series object. If only data or quality have been 
%% changed the we need to prevent syncts from trggering a @timeseries 
%% datachange event listener which will needlessly try
%% to update the tstable using the synctable method causing a flicker. 
%% If a time has chnaged or a new row has been added the table must be
%% refeshed (with a potential flicker) since the order of rows may have
%% changed
if col>0  && this.Timeseries.TimeInfo.length+length(this.Timeseries.events)>=size(tableData,1)
    this.Tslistener.Enabled = 'off';
    this.syncts;
    this.Tslistener.Enabled = 'on';
    if ~isempty(this.up) && ishandle(this.up)
        this.up.send('timeserieschange')
    end
else
    this.syncts;
end

function localAddRow(eventSrc, eventData, h)

h.addRow;
  
function localDeleteRow(eventSrc, eventData, h)

h.deleteRow;
  
function localTSListUpdate(eventSrc,eventData,tscombo,manager)

%% Listener to @tsnodes being added or deleted which updates the 
%% combo box on the time series editor panel

tslist = eventSrc.getChildren;

%% If a node is being deleted, exclude it from the list
if ~isempty(eventData) && strcmp(eventData.Type,'ObjectChildRemoved')
    tslist = setdiff(tslist, eventData.Child);
end

%% Get the currently selected time series in the combo
tsComboList = get(tscombo,'String');
selectedTs = tsComboList{get(tscombo,'Value')};

%% If the previosly selected time series is on the new list make sure it
%% stays selected
if ~isempty(eventData) && strcmpi(eventData.Type,'New')
    ind = find(strcmp(eventData.Node.Label,get(tslist,{'Label'})));
else
    ind = find(strcmp(selectedTs,get(tslist,{'Label'})));
end
if isempty(ind)
    ind = 1;
end

%% Update the combo box with the list of current @tsnodes
if ~isempty(tslist)
  set(tscombo,'Enable','on','String',get(tslist,{'Label'}),'Value',ind(1));
else
  set(tscombo,'Enable','off','String',{' '},'Value',1); 
end


          
function localCalendar(eventSrc, eventData, h, type)

%% Calendar button callback

%% The Calendar dialog is a singleton for the @tsnode. If one does not
%% yet exist, create it
if isempty(h.Calendar)
    h.Calendar = tsguis.calendar;
    if ~isempty(h.Timeseries.TimeInfo.StartDate)
        if strcmp(type,'start')
            thisdatenum = datenum(h.Timeseries.TimeInfo.StartDate)+ ...
                h.Timeseries.TimeInfo.Start*tsunitconv('days',h.Timeseries.TimeInfo.Units);
        else
            thisdatenum = datenum(h.Timeseries.TimeInfo.StartDate)+ ...
                h.Timeseries.TimeInfo.End*tsunitconv('days',h.Timeseries.TimeInfo.Units);
        end
    else
        thisdatenum = now;
    end
else
    thisdatenum = h.Calendar.DateNum;
end

%% Parent the calendar to the current @tsnode
thisCalendar = h.Calendar;
thisCalendar.Updatefcn = ...
    @(es,ed) setUniformTime(h,get(thisCalendar,'DateNum'),get(thisCalendar,'Type'));
thisCalendar.Parent = h;
thisCalendar.Type = type;

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

%% The opening date is either the start/end date of an absolute time vector or
%% "now" if the time vector is relative
h.Calendar.DateNum = thisdatenum;


%% Open the calendar
h.Calendar.open

function localTablePnlResize(eventSrc, eventData, BTNattributes, ...
    BTNaddrow,BTNdelrow,CHKevents,PNLtable)

%% Table panel resize function keeps the buttons on the bottom right hand
%% corner - the table takes up the remaining space
pos = get(eventSrc, 'Position');
set(BTNattributes,'Position',[max(1,pos(3)-52.4) 1 21.4 1.4611]);
set(BTNaddrow,'Position',[max(1,pos(3)-30) 1 14 1.46 ]);
set(BTNdelrow,'Position',[max(1,pos(3)-15) 1 14 1.46 ]);
set(CHKevents,'Position',[1 1 40 1.46 ]);
tablePos =  hgconvertunits(ancestor(PNLtable,'figure'),...
             [1 3.46 max(1,pos(3)-2) max(1,pos(4)-3.46-1)],...
            'Characters','Pixels',get(PNLtable,'Parent'));
set(PNLtable,'Position',tablePos);

function localViewListUpdate(eventSrc, eventData, COMBexistview, ...
    RADIOexist,RADIOnew,EDITnewview, manager)

%% Callback to Viewnode ObjectChildAdded ObjectChildDeleted

if ~ishandle(manager.figure) % Being closed
    return
end

viewlist = setdiff(manager.Root.TsViewer.ViewsNode.find('-depth',2),...
    manager.Root.TsViewer.ViewsNode.find('-depth',1));

%% If a node is being deleted, exclude it from the list
if ~isempty(eventData) && strcmp(eventData.Type,'ObjectChildRemoved')
    viewlist = setdiff(viewlist, eventData.Child);
end

%% Update the combo box with the list of current @viewnodes
if ~isempty(viewlist)
    set(COMBexistview,'Enable','on','String',get(viewlist,{'Label'}));
    set(RADIOexist,'Enable','on')
else
    set(COMBexistview,'String',{' '},'Enable','off');
    set(RADIOexist,'Enable','off')
    set(RADIOexist,'Value',false)
    set(RADIOnew,'Value',true)
end     

%% Update the new view edit box to it does not overlap with an existing
%% view name
k = 1;
while any(strcmp(sprintf('%s%d','Default view',k),get(viewlist,{'Label'})))
    k=k+1;
end
set(EDITnewview,'String',sprintf('%s%d','Default view',k));

function localView(eventStc, eventData, h)

%% Display button callback

%% If the existing view radio button is selected find the view node
%% node
if get(h.Handles.RADIOexist,'Value')>0.5
    ind = get(h.Handles.COMBexistview,'Value');
    availableViews = get(h.Handles.COMBexistview,'String');
    % TO DO: replace tsguis.tsseriesview by its parent class - when
    % implemented
    allViews = setdiff(h.getRoot.tsViewer.ViewsNode.find(...
        '-depth',2),h.getRoot.tsViewer.ViewsNode.find('depth',1));
    selectedViewNodePos = ...
        strcmp(availableViews{ind},get(allViews,{'Label'}));
    selectedView = allViews(selectedViewNodePos);
%% If the new view radio button is selected create the @tsseriesview node
else
    % Get new view name
    newplotname = get(h.Handles.EDITnewview,'String');
    if isempty(newplotname)
        errordlg('You must specify a name for the new view',...
            'Time Series Tools','modal')
        return
    end
    
    % Get new view type
    viewnames = get(h.Handles.COMBViewType,'String');
    newviewtype = viewnames{get(h.Handles.COMBViewType,'Value')};
    
    % Create new view
    %drawnow
    selectedView = ...
        h.getRoot.tsViewer.ViewsNode.getChildren('Label',newviewtype).addplot(...
              h.getRoot.TsViewer.TreeManager,newplotname);
end
 
%% Add the @timeseries to the selected @tsseriesview node
selectedView.addTs(h.Timeseries);


function localApply(eventSrc,eventData,h)

%% Apply button callback which updates to the specfied uniform time vector

%% Get the units
unitlist = get(h.Handles.COMBunits,'String');
newunits = unitlist{get(h.Handles.COMBunits,'Value')};

%% Get the format
formatstrs = get(h.Handles.COMBformat,'String');
formatstr = formatstrs{get(h.Handles.COMBformat,'Value')};
if ~strcmp(formatstr,'Numerical')
   h.Timeseries.TimeInfo.Format = formatstr;
else
   h.Timeseries.TimeInfo.Format = '';
end

%% Get the start end end times (and format)
%% Relative time
if get(h.Handles.RADIOrelTime,'Value') % Relative formatted time 
    h.Timeseries.TimeInfo.StartDate = '';
    if ~strcmp(formatstr,'Numerical')
        try % Round dates to the nearest second to avoid small rounding errors tuncating the time vec
            start = (round((datenum(get(h.Handles.EDITstart,'String'),formatstr)-...
                datenum('00:00:00'))*3600*24)/(3600*24))...
                * tsunitconv(newunits,'days');
        catch % Invalid entry - abort
            set(h.Handles.EDITstart,'String',datestr(h.Timeseries.TimeInfo.Start*tsunitconv('days',...
                h.Timeseries.TimeInfo.Units),formatstr));
            return
        end
        try 
            finish = (round((datenum(get(h.Handles.EDITend,'String'),formatstr)-...
                datenum('00:00:00'))*3600*24)/(3600*24))...
                * tsunitconv(newunits,'days');
        catch % Invalid entry - abort 
             set(h.Handles.EDITend,'String',datestr(h.Timeseries.TimeInfo.End*tsunitconv('days',...
                h.Timeseries.TimeInfo.Units),formatstr));
            return
        end
    else % Relative time - numeric format
        start = eval(get(h.Handles.EDITstart,'String'),'[]');
        finish = eval(get(h.Handles.EDITend,'String'),'[]');
        if ~isempty(start)
            set(h.Handles.EDITstart,'String',sprintf('%.12g',start));
        else % Invalid entry - abort
            set(h.Handles.EDITstart,'String',sprintf('%.12g',h.TimeSeries.TimeInfo.Start));
            return
        end
        if ~isempty(finish)
            set(h.Handles.EDITend,'String',sprintf('%.12g',finish));
        else % Invalid entry - abort
            set(h.Handles.EDITend,'String',sprintf('%.12g',h.TimeSeries.TimeInfo.End));
            return
        end
    end
else 
    % Check that there are no events
    if ~isempty(h.Timeseries.Events)
        ButtonName = questdlg('All events will be detached from this time series if the time vector is converted to absolute form?', ...
                       'Time Series Tool', 'Continue','Abort','Continue');
        if strcmp(ButtonName,'Abort')
            return
        else
            h.Timeseries.Events = [];
        end
    end
    % Check that valid dates have been entered
    try
        startdate = datenum(get(h.Handles.EDITstart,'String'));
        if isempty(startdate)
            error('Invalid date')
        end
    catch % If the time series is absolute write back date formatted start and end times, else use now
        if ~isempty(h.Timeseries.TimeInfo.StartDate)
            set(h.Handles.EDITstart,'String',h.Timeseries.TimeInfo.StartDate);
        else
            set(h.Handles.EDITstart,'String',datestr(now,formatstr));
        end    
        return
    end
    try 
        enddate  = datenum(get(h.Handles.EDITend,'String'));
        if isempty(enddate)
            error('Invalid date')
        end
    catch % If the time series is absolute write back date formatted start and end times, else use now
        if ~isempty(h.Timeseries.TimeInfo.StartDate)
            set(h.Handles.EDITend,'String',datestr(datenum(h.Timeseries.TimeInfo.StartDate)+...
                tsunitconv('days',h.Timeseries.TimeInfo.Units)*h.Timeseries.TimeInfo.End,formatstr))
        else
            set(h.Handles.EDITend,'String',datestr(now+h.Timeseries.TimeInfo.Length,formatstr))
        end
        return
    end
        
    h.Timeseries.TimeInfo.StartDate = get(h.Handles.EDITstart,'String');
    start = 0;
    startdatenum = datenum(get(h.Handles.EDITstart,'String'),...
        h.Timeseries.TimeInfo.Format);
    enddatenum = datenum(get(h.Handles.EDITend,'String'),...
        h.Timeseries.TimeInfo.Format);
    finish = round(3600*24*(-startdatenum+enddatenum))*tsunitconv(newunits,'days')/(3600*24);
end
if finish<start
    errordlg('The end time must be greater than the start time',...
        'Time Series Tool','modal')
    return
end
%% Get the interval
incr = eval(get(h.Handles.EDITinterval,'String'),'[]');
if isempty(incr) || ~isnumeric(incr) || ~isscalar(incr) || incr<=0
    errordlg('Invalid interval','Time Series Tools','modal')
    return
end

%% Set the units and format
h.Timeseries.TimeInfo.Units = newunits;

%% Reset the time vector
if (finish-start)/incr>100000
    errordlg('Time series length exceeds 100000. Verify that you have specified the correct units',...
        'Time Series Tools','modal')
    return
end

if isscalar(start) && isscalar(finish) && isscalar(incr) && finish>=start
    h.settime(start:incr:finish);
else
    errordlg('Invalid time specification','Time Series Tools','modal')
end

function localTsComboCallback(eventSrc,eventData,h,manager)

%% Time series combo callback which selects the corresponding time series
%% in the tree view

tscombostr = get(eventSrc,'String');
tsnodes = h.up.getChildren;
I = find(strcmp(tscombostr{get(eventSrc,'Value')},get(tsnodes,{'Label'})));
Iold = find(h==tsnodes);
if ~isempty(I)
    manager.Tree.setSelectedNode(tsnodes(I(1)).getTreeNodeInterface);
end

%% Set the combo back to its former value so that the Dialog panel remains
%% in sync with its corresponding node. This creates the illusion that the
%% view selection panel is independent of the selected node
if ~isempty(Iold)
   set(eventSrc,'value',Iold(1))
end

function localAbsRelChange(es,ed,h)

%% Get format strings
[formstrs,absstatus] = tsgetDateFormat;

%% Callback for the absolute/relative time radio buttons

if get(h.Handles.RADIOrelTime,'Value')
    % Set the contents of the format combo to be time formats
    set(h.Handles.COMBformat,'String',[{'Numerical'}; formstrs(~[absstatus{:}])],...
        'Value',1)
    set(h.Handles.BTNstart,'Enable','off')
    set(h.Handles.BTNend,'Enable','off')
    set(h.Handles.EDITstart,'String',sprintf('%.12g',h.Timeseries.TimeInfo.Start))
    set(h.Handles.EDITend,'String',sprintf('%.12g',h.Timeseries.TimeInfo.End))
else
    % Initialize the units if this is the initial display
    if isempty(es)
        set(h.Handles.COMBunits,'Value',...
            find(strcmp(h.Timeseries.TimeInfo.Units,get(findtype('TimeUnits'),...
            'Strings'))))
    end
    unitlist = get(h.Handles.COMBunits,'String');
    theseunits = unitlist{get(h.Handles.COMBunits,'Value')};
    set(h.Handles.BTNstart,'Enable','on')
    set(h.Handles.BTNend,'Enable','on')
    if ~isempty(h.Timeseries.TimeInfo.Format) && ~isempty(find(strcmp(h.Timeseries.TimeInfo.Format,formstrs([absstatus{:}]))))
        % time series object contains a format which indicates absolute
        % dateformat
        set(h.Handles.COMBformat,'String',formstrs([absstatus{:}]),'Value',...
            find(strcmp(h.Timeseries.TimeInfo.Format,formstrs([absstatus{:}]))));
    else
        % time series object contains a relative time format, including
        % HH:MM:SS
        set(h.Handles.COMBformat,'String',formstrs([absstatus{:}]),'Value',1);
    end
    if ~isempty(h.Timeseries.TimeInfo.StartDate)
        starttime = tsunitconv('days',theseunits)*...
            h.Timeseries.TimeInfo.Start+datenum(h.Timeseries.TimeInfo.StartDate);
        endtime = tsunitconv('days',theseunits)*...
            h.Timeseries.TimeInfo.End+datenum(h.Timeseries.TimeInfo.StartDate);
    else
        % use floor(now) to get date only
        starttime = tsunitconv('days',theseunits)*...
            h.Timeseries.TimeInfo.Start+floor(now);
        endtime = tsunitconv('days',theseunits)*...
            h.Timeseries.TimeInfo.End+floor(now);
    end
    % Update the start and end times
    formatstr = get(h.Handles.COMBformat,'String');
    thisformat = formatstr{get(h.Handles.COMBformat,'Value')};
    set(h.Handles.EDITstart,'String',sprintf('%s',datestr(starttime,thisformat)))
    set(h.Handles.EDITend,'String',sprintf('%s',datestr(endtime,thisformat)))
    % removed: so the radio button choice chage won't affect the unit
    % Set the interval units to days
%     set(h.Handles.COMBunits,'Value',...
%         find(strcmp('days',get(findtype('TimeUnits'),'Strings'))))
end


function localsetFormat(es,ed,h)

%% Format combo button callback resets the format of the start and end
%% times
formatstr = get(h.Handles.COMBformat,'String');
thisformat = formatstr{get(h.Handles.COMBformat,'Value')};
unitlist = get(h.Handles.COMBunits,'String');
theseunits = unitlist{get(h.Handles.COMBunits,'Value')};
    
if get(h.Handles.RADIOrelTime,'Value') 
    

    [thisstarttime,ct,errstr] = sscanf(get(h.Handles.EDITstart,'String'),'%f');
    if ~isempty(errstr)
        thisstarttime = [];
    end
    [thisendtime,ct,errstr] = sscanf(get(h.Handles.EDITend,'String'),'%f');
    if ~isempty(errstr)
        thisendtime = [];
    end
    
    if ~strcmp(thisformat,'Numerical')
        % Start time has been entered numerically - convert it to the right
        % time format
        if ~isempty(thisstarttime) 
            thisstarttime = datestr(thisstarttime*tsunitconv('days',theseunits),...
                thisformat);
        % Start time has been defined using a formatted string or is empty.
        % If necessary, convert the format to that specific in the format combo    
        else   
            thisstarttime = get(h.Handles.EDITstart,'String');
            if ~isempty(thisstarttime)
                try 
                    thisstarttime = datestr(thisstarttime,thisformat);
                catch 
                    thisstarttime = '';
                end
            end
        end
        % End time has been entered numerically - convert it to the right
        % time format
        if ~isempty(thisendtime)
            thisendtime = datestr(thisendtime*tsunitconv('days',theseunits),...
                thisformat);
        % End time has been defined using a formatted string or is empty.
        % If necessary, convert the format to that specific in the format
        % combo  
        else    
            thisendtime = get(h.Handles.EDITend,'String');
            if ~isempty(thisendtime)
                try 
                    thisendtime = datestr(get(h.Handles.EDITend,'String'),thisformat);
                catch 
                    thisendtime = '';
                end
            end
        end    
    else % Numeric format
        if isempty(thisstarttime) % Try to convert formatted time back to numeric
            try
                thisstarttime = (datenum(get(h.Handles.EDITstart,'String'))-...
                    datenum('00:00:00','HH:MM:SS'))*...
                    tsunitconv(theseunits,'days');
            catch
                thisstarttime = '';
            end
        else % Time is already numeric
            thisstarttime = num2str(thisstarttime);
        end
        if isempty(thisendtime) % Try to convert formatted time back to numeric
            try
                thisendtime = (datenum(get(h.Handles.EDITend,'String'))-...
                    datenum('00:00:00','HH:MM:SS'))*...
                    tsunitconv(theseunits,'days');
            catch
                thisendtime = '';
            end
        else % Time is already numeric
            thisendttime = num2str(thisendtime);
        end
    end
else
    thisstarttime = datestr(get(h.Handles.EDITstart,'String'));
    thisstarttime = datestr(thisstarttime,thisformat);
    thisendtime = datestr(get(h.Handles.EDITend,'String'));
    thisendtime = datestr(thisendtime,thisformat);
end

set(h.Handles.EDITstart,'String',thisstarttime)
set(h.Handles.EDITend,'String',thisendtime)

function localUpdateTimeVec(es,ed,TimeInfo,TXTtimevector)

%% Listener callback for changes in the current time vector
if ~isempty(TimeInfo.StartDate)
    if tsIsDateFormat(TimeInfo.Format)
        startstr = datestr(datenum(TimeInfo.StartDate)+TimeInfo.Start*tsunitconv('days',...
            TimeInfo.Units),TimeInfo.Format);
        endstr = datestr(datenum(TimeInfo.StartDate)+TimeInfo.End*tsunitconv('days',...
            TimeInfo.Units),TimeInfo.Format);        
    else
        startstr = datestr(datenum(TimeInfo.StartDate)+TimeInfo.Start*tsunitconv('days',...
            TimeInfo.Units),'dd-mmm-yyyy HH:MM:SS');
        endstr = datestr(datenum(TimeInfo.StartDate)+TimeInfo.End*tsunitconv('days',...
            TimeInfo.Units),'dd-mmm-yyyy HH:MM:SS'); 
    end
    if isnan(TimeInfo.Increment)
        dispmsg = sprintf('Current time vector: %s to %s non-uniform',...
            startstr,endstr);
    else
        dispmsg = sprintf('Current time vector: %s to %s uniform',...
            startstr,endstr);
    end
else
    if isnan(TimeInfo.Increment)
        dispmsg = sprintf('Current time vector: %.12g to %.12g non-uniform with units %s',...
            TimeInfo.Start,TimeInfo.End,TimeInfo.Units);
    else
        dispmsg = sprintf('Current time vector: %.12g to %.12g uniform with interval %.12g %s(s)',...
            TimeInfo.Start,TimeInfo.End,TimeInfo.Increment,TimeInfo.Units);
    end
end    
set(TXTtimevector,'String',dispmsg)

function localDataResize(es,ed,h)

%% Data panel resize fcn
pos = get(es,'Position');
%disp('localDataResize')

if get(h.Handles.CHKevents,'Value')>0.5
    set(h.Handles.PNLtstable,'Position',[1 pos(4)*.4 max(1,pos(3)-2) max(1,pos(4)*.6-1)]);
    set(h.Handles.PNLevents,'Position',[1 .5 max(1,pos(3)-2) pos(4)*.4]);
else
    set(h.Handles.PNLtstable,'Position',[1 1 max(1,pos(3)-2) max(1,pos(4)-2)]);
end

function localShowEventTable(es,ed,h)

%% Events checkbox callback which shown the event pane
if get(h.Handles.CHKevents,'Value')
    set(h.Handles.PNLevents,'Visible','on');
else
    set(h.Handles.PNLevents,'Visible','off');
end
localDataResize(h.Handles.PNLdata,[],h);