classdef (Hidden) AbstractToolData < mrtool.data.AbstractData
    % Abstract Data Class for Tools in Model Reduction App
    
    % Author(s): Suat Gumussoy
    % Copyright 2015 The MathWorks, Inc. 
    
    properties(Access = protected, SetObservable = true, AbortSet = true)
        ReducedSystem
        Options
        ShowSystemResponse = true;
        ShowAdditiveDifferencePlot = false;
        ShowMultiplicativeDifferencePlot = false;
        EventManager = [];
        EventManagerEnabled = false;
        UsedInEmbeddedApps = false;
    end  
    properties (Hidden)
        IsDirty = false;
    end    
    properties (Transient)
        ToolDataChangedListener
    end        
    methods (Access = public)        
        %% Constructor
        function this = AbstractToolData(Target,TargetList,Options)
            this = this@mrtool.data.AbstractData(Target,TargetList);
            if nargin<3
                setOptions(this);
            else
                setOptions(this,Options);
            end            
        end 
        function setEventManager(this,EventManager)
            this.EventManager = EventManager;
        end
        function EventManager = getEventManager(this)
            EventManager = this.EventManager;            
        end
        function enableEventManager(this,flag)
            this.EventManagerEnabled = flag;            
        end
        function postMessage(this,msg,WaitbarStatus)
            if nargin<3
                WaitbarStatus = 'on';
            end
            if this.EventManagerEnabled
                postActionStatus(getEventManager(this),WaitbarStatus,mrtool.util.convertStr2Html(msg));
            end                            
        end
        function clearMessage(this)
            if this.EventManagerEnabled
                clearActionStatus(getEventManager(this));
            end            
        end
        %% Reduced System
        function computeReducedSystem(this,loadingFlag)
            if ~this.UsedInEmbeddedApps
                if nargin<2
                    loadingFlag=false;
                end
                postMessage(this,getString(message('Control:mrtool:StatusMessageComputingReducedModel')));
                ReducedSystem = localComputeReducedSystem(this);
                ReducedSystem.SamplingGrid = struct('Order',order(ReducedSystem));
                setReducedSystem(this,ReducedSystem,loadingFlag);
                clearMessage(this);
            end
        end
        function setReducedSystem(this,ReducedSystem,loadingFlag)
            if ~isa(ReducedSystem,'DynamicSystem')
                error(message('Control:mrtool:ErrorDynamicSystem'));
            else                
                this.ReducedSystem = ReducedSystem;
                fireToolDataChangedEvent(this,loadingFlag);
            end                            
        end
        function System = getReducedSystem(this,loadingFlag)
            if nargin<2
                loadingFlag=false;
            end            
            if isempty(this.ReducedSystem)
                computeReducedSystem(this,loadingFlag)                
            end
            System = this.ReducedSystem;
        end
        function Model = getReducedModel(this)
            Model = mrtool.data.ModelWrapper(getTargetName(this),getReducedSystem(this));                   
        end
        function fireToolDataChangedEvent(this,loadingFlag)
            notify(this,'ToolDataChanged');
            if ~loadingFlag
                setDirty(this,true);
            end
        end
        %% Options
        function Options = getOptions(this)
            Options = this.Options;
        end
        function setOptionsField(this,FieldName,FieldValue)
            try
                CurrentOptions = this.getOptions;
                if ~isequal(CurrentOptions.(FieldName),FieldValue)
                    CurrentOptions.(FieldName) = FieldValue;
                    setOptions(this,CurrentOptions);
                end
            catch
                switch FieldName
                    case 'AbsTol'
                        error(message('Control:mrtool:ErrorAbsTol'));
                    case 'RelTol'
                        error(message('Control:mrtool:ErrorRelTol'));
                    case 'Offset'
                        error(message('Control:mrtool:ErrorOffset'));
                    otherwise
                        error('Unknown options field');
                end                                
            end            
        end 
        function createReducedSystem(this)
            % create multiple models if exists
            Model = getReducedModel(this);
            nModel = numsys(Model.System);
            if nModel>1
                for ct=1:nModel
                    NewModel = mrtool.data.ModelWrapper(Model.Name,Model.System(:,:,ct));
                    ed = ctrluis.toolstrip.dataprocessing.GenericEventData( ...
                        struct('Action','CreateSystem','ReducedModel',NewModel));
                    notify(this,'CreateReducedModel_ToolData',ed);
                end
            else
                ed = ctrluis.toolstrip.dataprocessing.GenericEventData( ...
                    struct('Action','CreateSystem','ReducedModel',Model));
                notify(this,'CreateReducedModel_ToolData',ed);
            end                        
        end    
        %% Visualizations
        function setShowSystemResponse(this,Flag)
            if ~islogical(Flag)
                error(message('Control:mrtool:ErrorVisualizationSelection'));
            end         
            this.ShowSystemResponse = Flag;
            notify(this,'PlotChanged');
%           setDirty(this,true);
        end
        function setShowAdditiveDifferencePlot(this,Flag)
            if ~islogical(Flag)
                error(message('Control:mrtool:ErrorVisualizationSelection'));
            end         
            this.ShowAdditiveDifferencePlot = Flag;
            notify(this,'PlotChanged');
%           setDirty(this,true);
        end        
        function setShowMultiplicativeDifferencePlot(this,Flag)
            if ~islogical(Flag)
                error(message('Control:mrtool:ErrorVisualizationSelection'));
            end         
            this.ShowMultiplicativeDifferencePlot = Flag;
            notify(this,'PlotChanged');
%           setDirty(this,true);
        end
        function setVisualizations(this,Selection)
            switch find(Selection)
                case 1
                    setShowSystemResponse(this,true);
                case 2
                    setShowAdditiveDifferencePlot(this,true);
                case 3
                    setShowMultiplicativeDifferencePlot(this,true);
            end                                
        end
        function Result = getShowSystemResponse(this)
            Result = this.ShowSystemResponse;
        end
        function Result = getShowAdditiveDifferencePlot(this)
            Result = this.ShowAdditiveDifferencePlot;
        end    
        function Result = getShowMultiplicativeDifferencePlot(this)
            Result = this.ShowMultiplicativeDifferencePlot;
        end
        %% Load/Save Session
        function loadSession(this,SessionData)            
            if ~isequal(getTarget(this),SessionData.Target)
                this.Target = SessionData.Target;
            end                        
            loadSessionToolData(this,SessionData); % loading session data specific to tool data
        end
        function SessionData = saveSession(this,SessionData)
            SessionData.Target = this.Target;
            SessionData.Visualizations = [getShowSystemResponse(this); getShowAdditiveDifferencePlot(this); getShowMultiplicativeDifferencePlot(this)];
            % append tool data specific to individual tool
            SessionData = saveSessionToolData(this,SessionData);
        end
        function setDirty(this,flag)
            if flag
                a=1;
            end
            this.IsDirty = flag;            
        end
        %% For Embedded Apps
        function setUsedInEmbeddedApps(this,flag)
            this.UsedInEmbeddedApps = flag;
        end
        function flag = isUsedInEmbeddedApps(this)
            flag = this.UsedInEmbeddedApps;
        end
    end
    methods (Abstract)
        setOptions(this);   
    end
    methods (Abstract, Access=protected)
        localComputeReducedSystem(this);        
    end
    events
        ToolDataChanged
        ReducedSystemChanged
        PlotChanged
        CreateReducedModel_ToolData
        FrequencyRangeChanged        
    end  
end
