classdef(Hidden,Sealed) FigureFactory < handle
    %FIGUREFACTORY Factory class for producing figure documents in the
    %econModeler app
    
    %Copyright 2017-2019 The Mathworks Inc.
    
    properties
        Session
        Listeners
    end
    
    methods(Access = ?internal.EconModeler.econModelerSession)
        function this = FigureFactory(session)
            this.Session = session;
            this.Listeners{end+1} = event.listener(this.Session,'TimeSeriesRegistered',@(s,e)reactToNewTimeSeries(this,s,e));
            this.Listeners{end+1} = event.listener(this.Session,'ModelRegistered',@(s,e)reactToNewModel(this,s,e));
            this.Listeners{end+1} = event.listener(this.Session,'NewPlotRequest',@(s,e)determinePlotType(this,s,e));
            this.Listeners{end+1} = event.listener(this.Session,'NewTestRequest',@(s,e)determineTestType(this,s,e));
        end
        
    end
    
    methods (Access = private)
        
        function determinePlotType(this,~,e)
           import internal.EconModeler.Enumerations.PlotTypes
           
           selections = this.Session.getSelections();
           if isrow(selections)
               selections = selections';
           end
           
           if e.RequestedPlot == PlotTypes.TSPLOT
               figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.TSPlot');
               if ~isempty(figureToShow)
                   figureToShow.Selected = true;
               else
                createTimeSeriesPlot(this,selections);
               end
           elseif e.RequestedPlot == PlotTypes.YY
               figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.YYPlot');
               if ~isempty(figureToShow)
                   figureToShow.Selected = true;
               else
                createYYPlot(this,selections);
               end
           elseif e.RequestedPlot == PlotTypes.ACF
               figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.ACFPlot');
               if ~isempty(figureToShow)
                   figureToShow.Selected = true;
               else
                   createACFPlot(this,selections);
               end
           elseif e.RequestedPlot == PlotTypes.ACF2
               figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.ACF2Plot');
               if ~isempty(figureToShow)
                   figureToShow.Selected = true;
               else
                   createACF2Plot(this,selections);
               end
           elseif e.RequestedPlot == PlotTypes.PACF
               figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.PACFPlot');
               if ~isempty(figureToShow)
                   figureToShow.Selected = true;
               else
                   createPACFPlot(this,selections);
               end
           elseif e.RequestedPlot == PlotTypes.CORRS
               figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.CorrelationsPlot');
               if ~isempty(figureToShow)
                   figureToShow.Selected = true;
               else
                   createCorrelationsPlot(this,selections);
               end
           elseif e.RequestedPlot == PlotTypes.FIT
               figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.ModelFitPlot');
               if ~isempty(figureToShow)
                   figureToShow.Selected = true;
               else
                   createModelFitPlot(this,selections);
               end
           elseif e.RequestedPlot == PlotTypes.HIST
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.HistogramPlot');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                   createHistogramPlot(this,selections);
                end
           elseif e.RequestedPlot == PlotTypes.QQ
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.QQPlot');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                    createQQPlot(this,selections);
                end
           end
        end
        
        function determineTestType(this,~,e)
            import internal.EconModeler.Enumerations.TestTypes
            
            selections = this.Session.getSelections();
            
            if e.RequestedTest == TestTypes.ADF
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.ADFFigure');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                    createADFFigure(this,selections);
                end
            elseif e.RequestedTest == TestTypes.KPSS
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.KPSSFigure');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                    createKPSSFigure(this,selections);
                end
            elseif e.RequestedTest == TestTypes.LMC
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.LMCFigure');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                    createLMCFigure(this,selections);
                end
            elseif e.RequestedTest == TestTypes.PP
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.PPFigure');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                   createPPFigure(this,selections);
                end
            elseif e.RequestedTest == TestTypes.VRATIO
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.VRationFigure');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                    createVRatioFigure(this,selections);
                end
            elseif e.RequestedTest == TestTypes.ARCH
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.ARCHFigure');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                    createARCHFigure(this,selections);
                end
            elseif e.RequestedTest == TestTypes.LBQ
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.LBQFigure');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                    createLBQFigure(this,selections);
                end
            elseif  e.RequestedTest == TestTypes.COLLIN
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.CollinPlot');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                   createCollinPlot(this,selections);
                end
            elseif e.RequestedTest == TestTypes.EGCI
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.EGCIFigure');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                   createEGCIFigure(this,selections);
                end
            elseif e.RequestedTest == TestTypes.JCI
                figureToShow = findFigureMatch(this,selections,'internal.EconModeler.EconComponents.Figures.JCIFigure');
                if ~isempty(figureToShow)
                   figureToShow.Selected = true;
                else
                   createJCIFigure(this,selections);
                end
            end
        end
            
        function reactToNewTimeSeries(this,~,e)
            tsToPlot = e.TimeSeries;
            createTimeSeriesPlot(this,tsToPlot);
        end
        
        function reactToNewModel(this,~,e)
            modelToPlot = e.Model;
            createModelFitPlot(this,modelToPlot);
        end
        
        function createModelFitPlot(this,modelToPlot)
            
            modelFitFigure = internal.EconModeler.EconComponents.Figures.ModelFitPlot(this.Session,modelToPlot);
            this.Session.addFigure(modelFitFigure);
            
            drawFigure(modelFitFigure);
            addToolbars(modelFitFigure);
        end
        
        function createTimeSeriesPlot(this,tsToPlot)
            tsPlotFigure = internal.EconModeler.EconComponents.Figures.TSPlot(this.Session,tsToPlot);
            this.Session.addFigure(tsPlotFigure);
            
            drawFigure(tsPlotFigure);
            
            addToolbars(tsPlotFigure);
        end
        
        function createYYPlot(this,tsToPlot)
            tsPlotFigure = internal.EconModeler.EconComponents.Figures.YYPlot(this.Session,tsToPlot);
            this.Session.addFigure(tsPlotFigure);
            
            drawFigure(tsPlotFigure);
            addToolbars(tsPlotFigure);
        end
        
        function createACFPlot(this,tsToPlot)
            
            acfFigure = internal.EconModeler.EconComponents.Figures.ACFPlot(this.Session,tsToPlot);
            this.Session.addFigure(acfFigure);
            
            drawFigure(acfFigure); 
            addToolbars(acfFigure);
        end
        
        function createACF2Plot(this,tsToPlot)
            
            acf2Figure = internal.EconModeler.EconComponents.Figures.ACF2Plot(this.Session,tsToPlot);
            this.Session.addFigure(acf2Figure);
            
            drawFigure(acf2Figure);
            addToolbars(acf2Figure);
        end
        
        function createPACFPlot(this,tsToPlot)
            
            pacfFigure = internal.EconModeler.EconComponents.Figures.PACFPlot(this.Session,tsToPlot);
            this.Session.addFigure(pacfFigure);
            
            drawFigure(pacfFigure);
            addToolbars(pacfFigure);
        end
        
        function createCrossCorrPlot(this,tsToPlot)
            
            crossCorrFigure = internal.EconModeler.EconComponents.Figures.CrossCorrPlot(this.Session,tsToPlot);
            this.Session.addFigure(crossCorrFigure);
            
            drawFigure(crossCorrFigure);
            addToolbars(crossCorrFigure);
        end
        
        function createCorrelationsPlot(this,tsToPlot)
            
            correlationsFigure = internal.EconModeler.EconComponents.Figures.CorrelationsPlot(this.Session,tsToPlot);
            this.Session.addFigure(correlationsFigure);
            
            drawFigure(correlationsFigure);  
            %Correlations plot doesn't get any toolbars
        end
        
        function createCollinPlot(this,tsToPlot)
            collinFigure = internal.EconModeler.EconComponents.Figures.CollinPlot(this.Session,tsToPlot);
            this.Session.addFigure(collinFigure);
            
            drawFigure(collinFigure);
            addToolbars(collinFigure);
        end
        
        function createADFFigure(this,tsToTest)
            
            adfFigure = internal.EconModeler.EconComponents.Figures.ADFFigure(this.Session,tsToTest);
            this.Session.addFigure(adfFigure);
            
            drawFigure(adfFigure);
            addToolbars(adfFigure);
        end
        
        function createKPSSFigure(this,tsToTest)
            kpssFigure = internal.EconModeler.EconComponents.Figures.KPSSFigure(this.Session,tsToTest);
            this.Session.addFigure(kpssFigure);
            
            drawFigure(kpssFigure);
            addToolbars(kpssFigure);
        end
        
        function createLMCFigure(this,tsToTest)
            lmcFigure = internal.EconModeler.EconComponents.Figures.LMCFigure(this.Session,tsToTest);
            this.Session.addFigure(lmcFigure);
            
            drawFigure(lmcFigure);
            addToolbars(lmcFigure);
        end
        
        function createPPFigure(this,tsToTest)
            ppFigure = internal.EconModeler.EconComponents.Figures.PPFigure(this.Session,tsToTest);
            this.Session.addFigure(ppFigure);
            
            drawFigure(ppFigure);
            addToolbars(ppFigure);
        end
        
        function createVRatioFigure(this,tsToTest)
            vRatioFigure = internal.EconModeler.EconComponents.Figures.VRatioFigure(this.Session,tsToTest);
            this.Session.addFigure(vRatioFigure);
            
            drawFigure(vRatioFigure);
            addToolbars(vRatioFigure);
        end
        
        function createARCHFigure(this,tsToTest)
            archFigure = internal.EconModeler.EconComponents.Figures.ARCHFigure(this.Session,tsToTest);
            this.Session.addFigure(archFigure);
            
            drawFigure(archFigure);
            addToolbars(archFigure);
        end
        
        function createLBQFigure(this,tsToTest)
            lbqFigure = internal.EconModeler.EconComponents.Figures.LBQFigure(this.Session,tsToTest);
            this.Session.addFigure(lbqFigure);
            
            drawFigure(lbqFigure);
            addToolbars(lbqFigure);
        end
        
        function createEGCIFigure(this,tsToTest)
            egciFigure = internal.EconModeler.EconComponents.Figures.EGCIFigure(this.Session,tsToTest);
            this.Session.addFigure(egciFigure);
            
            drawFigure(egciFigure);
            addToolbars(egciFigure);
        end
        
        function createJCIFigure(this,tsToTest)
            jciFigure = internal.EconModeler.EconComponents.Figures.JCIFigure(this.Session,tsToTest);
            this.Session.addFigure(jciFigure);
            
            drawFigure(jciFigure);
            addToolbars(jciFigure);
        end
        
        function createHistogramPlot(this,model)
            
            histPlot = internal.EconModeler.EconComponents.Figures.HistogramPlot(this.Session,model);
            this.Session.addFigure(histPlot);
            
            drawFigure(histPlot);
            addToolbars(histPlot);
        end
        
        function createQQPlot(this,model)
            
            qqPlot = internal.EconModeler.EconComponents.Figures.QQPlot(this.Session,model);
            this.Session.addFigure(qqPlot);
            
            drawFigure(qqPlot);
            addToolbars(qqPlot);
        end
        
        function figureToShow = findFigureMatch(this,selections,plotClass)
            allFigures = this.Session.getAllFigures;
            plotClassIdx = arrayfun(@(x)isa(x,plotClass),allFigures);
            plotsInClass = allFigures(plotClassIdx);
            matchIdx = arrayfun(@(x)length(x.Parent) == length(selections) && all(sort(x.Parent) == sort(selections)),plotsInClass);
            if any(matchIdx)
                indexToShow = find(matchIdx,1);
                figureToShow = plotsInClass(indexToShow);
            else
                figureToShow = internal.EconModeler.EconComponents.AbstractFigure.empty;
            end
        end
    end  
end

function addToolbars(econFig)
allAxes = findall(econFig.Value,'Type','Axes');
for n = 1:length(allAxes)
    internal.EconModeler.addGridAxesToolbar(allAxes(n));
end
end

