classdef (Hidden) PlotTabMLOnline < handle
    % Plot Tab of Model Reduction App
    % compatible with MATLAB Online
    %
    % Author(s): Suat Gumussoy

    % Copyright 2016 The MathWorks, Inc.
    
    properties(Access = private)
        Tool
        Widgets
        SelectedSystemList
        PlotsResultsGallery
        Tab
        % Selection
        CurrentSelectedSystem = {}; % a cell array of variable objects of systems 
    end
    properties (Transient)
        % Selection/Focus Listeners
        SelectionChangeListener
        PlotDeletedListener
    end
    
    methods
        function this = PlotTabMLOnline(Tool)
            this.Tab = matlab.ui.internal.toolstrip.Tab(getString(message('Control:mrtool:PlotTab')));
            this.Tab.Tag = 'PlotTab';
            this.Tool = Tool;
            createWidgets(this)
        end
        function setDataBrowserComponent(this,Comp)
            delete(this.SelectionChangeListener)
            this.SelectionChangeListener = event.listener(Comp,...
                'DataBrowserSelectionChanged',@(es,ed) callbackSelectionChanged(this,es,ed));
        end
        function delete(this)
            delete(this.SelectionChangeListener);
            delete(this.PlotDeletedListener);
            if isvalid(this.PlotsResultsGallery)
                delete(this.PlotsResultsGallery);
            end
        end
        function Tab = getTab(this)
            Tab = this.Tab;
        end
        function Widgets = getWidgets(this)
            Widgets = this.Widgets;
        end
        function resetGallery(this)
            updateSelection(this,this.CurrentSelectedSystem);
        end
        function updatePicker(this)
            resetGallery(this);
        end
        function callbackSelectionChanged(this,~,ed)
            if isempty(ed.Data)
                Data = [];
            else
                Data = [ed.Data.Item]';
            end
            if  ~isempty(this) && isvalid(this)
                updateSelection(this,Data)
            end
        end
        function loadSession(this)
            % add listeners to created plots
            existingplots = getResponsePlotList(getPlotManager(this.Tool));
            if ~isempty(existingplots)
                for ct=1:length(existingplots)
                    this.PlotDeletedListener = [this.PlotDeletedListener; ...
                        event.listener(getAppContainer(this.Tool),'ClientAction',@(es,ed) callbackPlotDestroyed(this, es,ed))];
                end
            end
            % update gallery
            updatePicker(this);
        end
    end
    methods (Access = private)
        function createWidgets(this)
            import matlab.ui.internal.toolstrip.*
            %% SYSTEM SECTION
            %this.SelectedSystemList = ListBox({getString(message('Control:mrtool:PlotNoSystemSelected'))},false);            
            this.SelectedSystemList = TextArea(getString(message('Control:mrtool:PlotNoSystemSelected')));
            this.SelectedSystemList.Editable = false;
            this.Widgets.SystemList = this.SelectedSystemList;
            
            % place them
            SystemSection = Section(getString(message('Control:mrtool:PlotSystemSection')));
            SystemSection.Tag = 'SystemSection';
            this.Widgets.SystemSection = SystemSection;
            fScaledSize = com.mathworks.util.ResolutionUtils.scaleSize(110);
            column1 = Column('Width',fScaledSize); 
            add(SystemSection,column1)
            add(column1,this.SelectedSystemList)
            
            %% PLOT SECTION
            popup = GalleryPopup('GalleryItemRowCount',1,'GalleryItemTextLineCount',1);
            popup.Tag = 'gallerypopup';
            NewPlotCategory = GalleryCategory(getString(message('Control:mrtool:PlotGalleryNewPlotTitle')));
            this.Widgets.NewPlotCategory = NewPlotCategory;
            NewPlotItems = LocalGetNewPlots(this,false);
            for ct=1:length(NewPlotItems)
                NewPlotCategory.add(NewPlotItems(ct));
            end                        
            popup.add(NewPlotCategory);
            
            this.PlotsResultsGallery = matlab.ui.internal.toolstrip.Gallery(popup, 'MaxColumnCount', 9, 'MinColumnCount', 3); 
            this.Widgets.Gallery = this.PlotsResultsGallery;
            ExistingPlotCategory = GalleryCategory(getString(message('Control:mrtool:PlotGalleryExistingPlotTitle')));
            this.Widgets.ExistingPlotCategory = ExistingPlotCategory;
            updateSelection(this,'');
                        
            % place them
            PlotSection = Section(getString(message('Control:mrtool:PlotPlotSection')));
            PlotSection.Tag = 'PlotSection';
            this.Widgets.PlotSection = PlotSection;
            column2 = Column();
            add(PlotSection,column2)
            add(column2,this.PlotsResultsGallery);
            
            %% Place sections
            this.Widgets.Tab = this.Tab;
            add(this.Tab,SystemSection);
            add(this.Tab,PlotSection);
            
            this.Widgets.CurrentSelectedSystem = this.CurrentSelectedSystem;            
            this.Widgets.PlotGalleryOverlayText = getOverlayText();
        end
        function updateSelection(this,newselection)
            import matlab.ui.internal.toolstrip.*
            if ~isempty(newselection)
                sysvars = LocalGetValidSystems(newselection);
            else
                sysvars = [];
            end
            if isempty(sysvars)
                this.CurrentSelectedSystem = [];
            else
                this.CurrentSelectedSystem = sysvars;
            end
            
            if ~isempty(this) && isvalid(this)   
                syncGalleryItemsAndPlots(this)
            end
            
            if ~isempty(this) && isvalid(this)
                if isempty(this.CurrentSelectedSystem)
                    this.SelectedSystemList.Value = getString(message('Control:mrtool:PlotNoSystemSelected'));
                    this.PlotsResultsGallery.TextOverlay = getOverlayText();
                    disableAll(this.PlotsResultsGallery.Popup)
                else
                    % Update label
                    % Get names for variable names
                    names = LocalGetVarNames(this.CurrentSelectedSystem);
                    str = sprintf('%s\n',names{:});
                    
                    this.SelectedSystemList.Value = str(1:end-1);
                    this.PlotsResultsGallery.TextOverlay = '';
                    enableAll(this.PlotsResultsGallery.Popup)
                end
            end
        end
    end
    methods (Static = true)
        function plotSystem(this,seldata)
            % Get the selection from the map
            try
                postActionStatus(getEventManager(this.Tool),'on',mrtool.util.convertStr2Html(getString(message('Control:mrtool:StatusMessagePlotting'))));
                if strcmp(seldata.Type,'New')
                    RPlot = createPlot(getPlotManager(this.Tool),this.CurrentSelectedSystem,seldata.Data);
                    this.PlotDeletedListener = [this.PlotDeletedListener; ...
                        event.listener(getAppContainer(this.Tool),'ClientAction',@(es,ed) callbackPlotDestroyed(this, es,ed))];
                else
                    % Existing
                    hplot = seldata.Data;
                    if ~isvalid(hplot)
                        str = getString(message('Control:mrtool:PlotNoLongerAvailable'));
                        errordlg(str,getString(message('Control:mrtool:toolName')));
                        return;
                    end
                    for ct = 1:numel(this.CurrentSelectedSystem)
                        addModel(hplot,this.CurrentSelectedSystem(ct));
                    end
                end
                clearActionStatus(getEventManager(this.Tool));
                resetGallery(this)
            catch Ex
                if strcmp(Ex.identifier,'Control:mrtool:PlotEmptySystem')
                    str = getString(message('Control:mrtool:PlotEmptySystem'));
                else
                    str = getString(message('Control:mrtool:PlotNotCompatibleSize'));
                end
                clearActionStatus(getEventManager(this.Tool));
                errordlg(str,getString(message('Control:mrtool:toolName')));
                return;
            end
        end
    end
    
end
function syncGalleryItemsAndPlots(this)
% Existing plots
existingplots = getResponsePlotList(getPlotManager(this.Tool));

% Add the existing plots category
if ~isempty(existingplots)   
    if numel(this.PlotsResultsGallery.Popup.getChildByIndex)==1
        this.PlotsResultsGallery.Popup.add(this.Widgets.ExistingPlotCategory,1);
    end
    
    existingitems = this.Widgets.ExistingPlotCategory.getChildByIndex;
    if isempty(existingitems)
        existingitemnames = {};
    else
        existingitemnames = {existingitems.Text};
    end
    % find new plots and item for them
    % find deleted plots and remove their item
    [~,ixnewplots,ixdeletedplots] = setxor({existingplots.Name},existingitemnames);
    if ~isempty(ixnewplots) 
        setBusy(this.PlotsResultsGallery,true);
        % add item for new plot
        for ct=1:length(ixnewplots)
            sel = struct('Type','Existing','Data',existingplots(ixnewplots(ct)));
            newitem =  LocalCreateGalleryItem(this,sel);                
            this.Widgets.ExistingPlotCategory.add(newitem);
        end
        setBusy(this.PlotsResultsGallery,false);
    end
    if ~isempty(ixdeletedplots)
        setBusy(this.PlotsResultsGallery,true);
        % remove item for deleted plot
        for ct=1:length(ixdeletedplots)
            this.Widgets.ExistingPlotCategory.remove(existingitems(ixdeletedplots(ct)));
        end
        setBusy(this.PlotsResultsGallery,false);
    end
else    
    % remove existing items since no plots
    existingitems = this.Widgets.ExistingPlotCategory.getChildByIndex;
    if ~isempty(existingitems)
        setBusy(this.PlotsResultsGallery,true);
        for ct=1:numel(existingitems)
            this.Widgets.ExistingPlotCategory.remove(existingitems(ct));
        end
        setBusy(this.PlotsResultsGallery,false);
    end
    drawnow;
    
    if ~isempty(this) && isvalid(this)
        if ~isempty(this.PlotsResultsGallery) && isvalid(this.PlotsResultsGallery)
            % gallery may be already deleted so check validity
            if numel(this.PlotsResultsGallery.Popup.getChildByIndex)==2
                this.PlotsResultsGallery.Popup.remove(this.Widgets.ExistingPlotCategory);
            end
        end
    end
end
end

function callbackPlotDestroyed(this,es,ed)
% Ignore client events coming from data-browser or parameter table
evtype = ed.EventData.EventType;
client = ed.EventData.Client;
if (isempty(client) || ~isa(client,'matlab.ui.Figure') || strcmp(client.Tag,'paramtable')) && ~strcmp(evtype,'CLOSING')
    return;
end

if strcmp(evtype,'CLOSED') || strcmp(evtype,'CLOSING')
    % First make sure deletion of the responses are finalized using
    % drawnow
    drawnow;
    if isvalid(this) % This isvalid is necessary to handle GUI closure
        updateSelection(this,this.CurrentSelectedSystem)
    end
end

end
function [items,plottypes] = LocalGetNewPlots(this,isfrd)
plottypes = mrtool.PlotEnum.getPlotTypes(isfrd);
% Add new plots
items = matlab.ui.internal.toolstrip.GalleryItem.empty;
for ct = 1:numel(plottypes)
    thisplot = plottypes(ct);
    sel = struct('Type','New','Data',thisplot);
    items(end+1) = LocalCreateGalleryItem(this,sel); %#ok<AGROW>
end
end
function item = LocalCreateGalleryItem(this,sel)
import matlab.ui.internal.toolstrip.*
thisplot = sel.Data;
if strcmp(sel.Type,'New')
    title = ctrlMsgUtils.message(...
        sprintf('Control:mrtool:PlotGalleryNew%s',char(thisplot)));
    Tag = thisplot.Tag;
else
    title = getName(thisplot);
    Tag = thisplot.PlotHandle.Tag;
end

item = GalleryItem(title,mrtool.PlotEnum.getIcon(Tag));
item.Description = title;
item.ItemPushedFcn = @(x,y) mrtool.tabs.PlotTabMLOnline.plotSystem(this,sel);
end
function sysvars = LocalGetValidSystems(sel)
for ct = numel(sel):-1:1
    valid(ct) = false;
    try
        sys = getModel(sel(ct));
        if isa(sys,'lti')
            valid(ct) = true;
        end
    catch
        continue;
    end
end
sysvars = sel(valid);
end
function names = LocalGetVarNames(sel)
names = cell(numel(sel),1);
for ct = 1:numel(sel)
    names{ct} = sel(ct).Name;
end
end
function str = getOverlayText()
str = getString(message('Control:mrtool:PlotGalleryOverlay'));
end