classdef UIVECComponentParameterDialog < handle
    %UIVECCOMPONENTPARAMETERDIALOG Dialog for setting VEC Model Parameters
    %using the Component Form
    
    %Copyright 2021 The MathWorks Inc.
    
    properties(Access = protected)
        Session internal.EconModeler.econModelerSession
        ModelType = internal.EconModeler.Enumerations.ModelTypes.VECComponent;
        Figure matlab.ui.Figure
        TabGroup matlab.ui.container.TabGroup
        OrderTab matlab.ui.container.Tab
        VectorTab matlab.ui.container.Tab
        FormOrderLabel matlab.ui.control.Label
        FormOrderDropDown matlab.ui.control.DropDown
        RankOrderLabel matlab.ui.control.Label
        RankOrderSpinner matlab.ui.control.Spinner
        LagOrderLabel  matlab.ui.control.Label
        LagOrderSpinner matlab.ui.control.Spinner
        AdjustmentOrderLabel matlab.ui.control.Label
        AdjustmentOrderButton matlab.ui.control.Button
        AdjustmentOrderTable matlab.ui.control.Table
        CointegrationOrderLabel matlab.ui.control.Label
        CointegrationOrderButton matlab.ui.control.Button
        CointegrationOrderTable matlab.ui.control.Table
        ShortRunOrderLabel matlab.ui.control.Label
        ShortRunOrderDropDown matlab.ui.control.DropDown
        ShortRunOrderButton matlab.ui.control.Button
        ShortRunOrderTable matlab.ui.control.Table
        FormVectorLabel matlab.ui.control.Label
        FormVectorDropDown matlab.ui.control.DropDown
        RankVectorLabel matlab.ui.control.Label
        RankVectorSpinner matlab.ui.control.Spinner
        LagVectorLabel  matlab.ui.control.Label
        LagVectorEdit matlab.ui.control.EditField
        AdjustmentVectorLabel matlab.ui.control.Label
        AdjustmentVectorButton matlab.ui.control.Button
        AdjustmentVectorTable matlab.ui.control.Table
        CointegrationVectorLabel matlab.ui.control.Label
        CointegrationVectorButton matlab.ui.control.Button
        CointegrationVectorTable matlab.ui.control.Table
        ShortRunVectorLabel matlab.ui.control.Label
        ShortRunVectorDropDown matlab.ui.control.DropDown
        ShortRunVectorButton matlab.ui.control.Button
        ShortRunVectorTable matlab.ui.control.Table
        ModelEqAxes matlab.ui.control.UIAxes
        ModelEqText matlab.graphics.primitive.Text
        EstimateButton matlab.ui.control.Button
        CancelButton matlab.ui.control.Button
        DetailsButton matlab.ui.control.Button
        TimeSeries internal.EconModeler.EconComponents.AbstractTimeSeries
        Listeners cell

        PreviousCointegrationMatrix double

        ShortRunOrderValues cell
        ShortRunVectorValues cell

    end
    
    methods(Access = ?internal.EconModeler.DialogFactory)
        function this = UIVECComponentParameterDialog(session,source)
            %UIVECCOMPONENTPARAMETERDIALOG Construct an instance of this class
            
            this.Session = session;

            if isa(source,'internal.EconModeler.EconComponents.AbstractModel')
                this.TimeSeries = source.Parent;
            else
                this.TimeSeries = source;
            end
            
            %Figure
            this.Figure = uifigure('Name',getString(message('econ:econModeler:VECComponentModelTitle')),...
                'CloseRequestFcn',@this.closeCallback,...
                'Visible','off',...
                'Tag','parameterFigure',...
                'WindowStyle','modal');
            this.Figure.Position = [680,558,725,600];

            matlab.graphics.internal.themes.figureUseDesktopTheme(this.Figure);

            this.ShortRunOrderValues = {nan(length(this.TimeSeries))};
            this.ShortRunVectorValues = {nan(length(this.TimeSeries))};

            %Outer Grid contains all controls
            outergrid = uigridlayout(this.Figure,[3 1],"RowHeight",{'3x','1x','fit'});

            this.TabGroup = uitabgroup(outergrid,'Tag','tagGroup',...
                'SelectionChangedFcn',@this.setModelEquation);
            this.TabGroup.Layout.Row = 1;
            this.OrderTab = uitab(this.TabGroup,'Title',getString(message('econ:econModeler:LagOrder')),'Tag','OrderTab');
            this.VectorTab = uitab(this.TabGroup,'Title',getString(message('econ:econModeler:LagVector')),'Tag','VectorTab');

            orderGrid = uigridlayout(this.OrderTab,[2 1],'RowHeight',{'1x','1x'},'RowSpacing',0);
            topOrderGrid = uigridlayout(orderGrid,[1 2],'ColumnWidth',{'fit','1x'},'Padding',[0 0 0 0]);
            topOrderGrid.Layout.Row = 1;
            
            topLeftOrderGrid = uigridlayout(topOrderGrid,[5 2],'RowHeight',{'1x','fit','fit','fit','1x'},...
                'ColumnWidth',{'fit','fit'});
            topLeftOrderGrid.Layout.Row = 1;
            topLeftOrderGrid.Layout.Column = 1;
            this.FormOrderLabel = uilabel(topLeftOrderGrid,'Text',getString(message('econ:econModeler:JohansenForm')),...
                'Tag','formLabel');
            this.FormOrderLabel.Layout.Row = 2;
            this.FormOrderLabel.Layout.Column = 1;
            this.FormOrderDropDown = uidropdown(topLeftOrderGrid,'Items',{'H2','H1*','H1','H*','H'},...
                'Value','H1','ValueChangedFcn',@this.setForm,...
                'Tag','formDropDown');
            this.FormOrderDropDown.Layout.Row = 2;
            this.FormOrderDropDown.Layout.Column = 2;
            this.RankOrderLabel = uilabel(topLeftOrderGrid,'Text',getString(message('econ:econModeler:Rank')),...
                'Tag','rankLabel');
            this.RankOrderLabel.Layout.Row = 3;
            this.RankOrderLabel.Layout.Column = 1;
            this.RankOrderSpinner = uispinner(topLeftOrderGrid,...
                'Value',1,'Step',1,'RoundFractionalValues','on','ValueChangedFcn',@this.setRank,...
                'Tag','rankSpinner');
            if length(this.TimeSeries) > 2
                this.RankOrderSpinner.Limits = [1,length(this.TimeSeries)-1];
                this.RankOrderSpinner.Enable = 'on';
            else
                this.RankOrderSpinner.Enable = 'off';
            end
            this.RankOrderSpinner.Layout.Row = 3;
            this.RankOrderSpinner.Layout.Column = 2;
            this.LagOrderLabel = uilabel(topLeftOrderGrid,'Text',getString(message('econ:econModeler:NumberOfLags')),...
                'Tag','LagLabel');
            this.LagOrderLabel.Layout.Row = 4;
            this.LagOrderLabel.Layout.Column = 1;
            this.LagOrderSpinner = uispinner(topLeftOrderGrid,'Limits',[1,inf],...
                'Value',1,'Step',1,'RoundFractionalValues','on','ValueChangedFcn',@this.setLags,...
                'Tag','lagSpinner');
            this.LagOrderSpinner.Layout.Row = 4;
            this.LagOrderSpinner.Layout.Column = 2;

            topRightOrderGrid = uigridlayout(topOrderGrid,[2 4],'RowHeight',{'fit','1x'},...
                'ColumnWidth',{'fit','fit','fit','1x'});
            topRightOrderGrid.Layout.Row = 1;
            topRightOrderGrid.Layout.Column = 2;
            this.ShortRunOrderLabel = uilabel(topRightOrderGrid,'Text',[getString(message('econ:econModeler:ShortRun')), ' (\Phi)'],...
                'Interpreter','tex','Tag','shortRunLabel');
            this.ShortRunOrderLabel.Layout.Row = 1;
            this.ShortRunOrderLabel.Layout.Column = 1;
            this.ShortRunOrderDropDown = uidropdown(topRightOrderGrid,...
                "Value",1,"Items",{getString(message('econ:econModeler:LagSelection',1))}, "ItemsData",1,...
                "ValueChangedFcn",@this.updateShortRunTable,...
                "Tag",'shortRunDropDown');
            this.ShortRunOrderDropDown.Layout.Row = 1;
            this.ShortRunOrderDropDown.Layout.Column = 2;
            this.ShortRunOrderButton = uibutton(topRightOrderGrid,"Text",getString(message('econ:econModeler:Import')),...
                "ButtonPushedFcn",@(s,e)this.importShortRun(s),'Tag','shortRunButton');
            this.ShortRunOrderButton.Layout.Row = 1;
            this.ShortRunOrderButton.Layout.Column = 3;
            this.ShortRunOrderTable = uitable(topRightOrderGrid,'Data',this.ShortRunOrderValues{1},...
                'RowName',{this.TimeSeries.Name},'ColumnName',{this.TimeSeries.Name},...
                'ColumnEditable',true,...
                'CellEditCallback',@this.setShortRun,'Tag','shortRunTable');
            this.ShortRunOrderTable.Layout.Row = 2;
            this.ShortRunOrderTable.Layout.Column = [1 4];

            bottomOrderGrid = uigridlayout(orderGrid,[1 2],'ColumnWidth',{'1x','1x'},'Padding',[0,0,0,0]);
            bottomOrderGrid.Layout.Row = 2;

            bottomLeftOrderGrid = uigridlayout(bottomOrderGrid,[2,3],'RowHeight',{'fit','1x'},...
                'ColumnWidth',{'fit','fit','1x'});
            bottomLeftOrderGrid.Layout.Row = 1;
            bottomLeftOrderGrid.Layout.Column = 1;
            this.AdjustmentOrderLabel = uilabel(bottomLeftOrderGrid,'Text',[getString(message('econ:econModeler:AdjustmentSpeed')),' (A)'],...
                'Interpreter','tex','Tag','adjustmentLabel');
            this.AdjustmentOrderLabel.Layout.Row = 1;
            this.AdjustmentOrderLabel.Layout.Column = 1;
            this.AdjustmentOrderButton = uibutton(bottomLeftOrderGrid,"Text",getString(message('econ:econModeler:Import')),...
                "ButtonPushedFcn",@(s,e)this.importAdjustment,'Tag','adjustmentButton');
            this.AdjustmentOrderButton.Layout.Row = 1;
            this.AdjustmentOrderButton.Layout.Column = 2;
            this.AdjustmentOrderTable = uitable(bottomLeftOrderGrid,'Data',nan(length(this.TimeSeries),this.RankOrderSpinner.Value),...
                'RowName',{this.TimeSeries.Name},...
                'ColumnEditable',true,'CellEditCallback',@this.setAdjustment,...
                'Tag','adjustmentTable');
            this.AdjustmentOrderTable.Layout.Row = 2;
            this.AdjustmentOrderTable.Layout.Column = [1 3];

            bottomRightOrderGrid = uigridlayout(bottomOrderGrid,[2, 3],'RowHeight',{'fit','1x'},...
                'ColumnWidth',{'fit','fit','1x'});
            bottomRightOrderGrid.Layout.Row = 1;
            bottomRightOrderGrid.Layout.Column = 2;
            this.CointegrationOrderLabel = uilabel(bottomRightOrderGrid,'Text',[getString(message('econ:econModeler:CointegrationMatrix')), ' (B)'],...
                'Interpreter','tex','Tag','cointegrationLabel');
            this.CointegrationOrderLabel.Layout.Row = 1;
            this.CointegrationOrderLabel.Layout.Column = 1;
            this.CointegrationOrderButton = uibutton(bottomRightOrderGrid,"Text",getString(message('econ:econModeler:Import')),...
                "ButtonPushedFcn",@(s,e)this.importCointegration,'Tag','cointegrationButton');
            this.CointegrationOrderButton.Layout.Row = 1;
            this.CointegrationOrderButton.Layout.Column = 2;
            this.CointegrationOrderTable = uitable(bottomRightOrderGrid,'Data',nan(length(this.TimeSeries),this.RankOrderSpinner.Value),...
                'RowName',{this.TimeSeries.Name},...
                'ColumnEditable',true,'CellEditCallback',@this.setCointegration,...
                'Tag','cointegrationTable');
            this.CointegrationOrderTable.Layout.Row = 2;
            this.CointegrationOrderTable.Layout.Column = [1 3];

            vectorGrid = uigridlayout(this.VectorTab,[2 1],'RowHeight',{'1x','1x'},'RowSpacing',0);
            topVectorGrid = uigridlayout(vectorGrid,[1 2],'ColumnWidth',{'fit','1x'},'Padding',[0 0 0 0]);
            topVectorGrid.Layout.Row = 1;
            
            topLeftVectorGrid = uigridlayout(topVectorGrid,[5 2],'RowHeight',{'1x','fit','fit','fit','1x'},...
                'ColumnWidth',{'fit','fit'});
            topLeftVectorGrid.Layout.Row = 1;
            topLeftVectorGrid.Layout.Column = 1;
            this.FormVectorLabel = uilabel(topLeftVectorGrid,'Text',getString(message('econ:econModeler:JohansenForm')),...
                'Tag','formLabel');
            this.FormVectorLabel.Layout.Row = 2;
            this.FormVectorLabel.Layout.Column = 1;
            this.FormVectorDropDown = uidropdown(topLeftVectorGrid,'Items',{'H2','H1*','H1','H*','H'},...
                'Value','H1','ValueChangedFcn',@this.setForm,...
                'Tag','formDropDown');
            this.FormVectorDropDown.Layout.Row = 2;
            this.FormVectorDropDown.Layout.Column = 2;
            this.RankVectorLabel = uilabel(topLeftVectorGrid,'Text',getString(message('econ:econModeler:Rank')),...
                'Tag','rankLabel');
            this.RankVectorLabel.Layout.Row = 3;
            this.RankVectorLabel.Layout.Column = 1;
            this.RankVectorSpinner = uispinner(topLeftVectorGrid,...
                'Value',1,'Step',1,'RoundFractionalValues','on','ValueChangedFcn',@this.setRank,...
                'Tag','rankSpinner');
            if length(this.TimeSeries) > 2
                this.RankVectorSpinner.Limits = [1,length(this.TimeSeries)-1];
                this.RankVectorSpinner.Enable = 'on';
            else
                this.RankVectorSpinner.Enable = 'off';
            end
            this.RankVectorSpinner.Layout.Row = 3;
            this.RankVectorSpinner.Layout.Column = 2;
            this.LagVectorLabel = uilabel(topLeftVectorGrid,'Text',getString(message('econ:econModeler:Lags')),...
                'Tag','LagLabel');
            this.LagVectorLabel.Layout.Row = 4;
            this.LagVectorLabel.Layout.Column = 1;
            this.LagVectorEdit = uieditfield(topLeftVectorGrid,...
                    'HorizontalAlignment','right',...
                    'Value','1',...
                    'ValueChangingFcn',@this.checkVectorText,...
                    'Tag','lagEdit');
            this.LagVectorEdit.Layout.Row = 4;
            this.LagVectorEdit.Layout.Column = 2;

            topRightVectorGrid = uigridlayout(topVectorGrid,[2 4],'RowHeight',{'fit','1x'},...
                'ColumnWidth',{'fit','fit','fit','1x'});
            topRightVectorGrid.Layout.Row = 1;
            topRightVectorGrid.Layout.Column = 2;
            this.ShortRunVectorLabel = uilabel(topRightVectorGrid,'Text',[getString(message('econ:econModeler:ShortRun')), ' (\Phi)'],...
                'Interpreter','tex','Tag','shortRunLabel');
            this.ShortRunVectorLabel.Layout.Row = 1;
            this.ShortRunVectorLabel.Layout.Column = 1;
            this.ShortRunVectorDropDown = uidropdown(topRightVectorGrid,...
                "Value",1,"Items",{getString(message('econ:econModeler:LagSelection',1))}, "ItemsData",1,...
                "ValueChangedFcn",@this.updateShortRunTable,...
                "Tag",'shortRunDropDown');
            this.ShortRunVectorDropDown.Layout.Row = 1;
            this.ShortRunVectorDropDown.Layout.Column = 2;
            this.ShortRunVectorButton = uibutton(topRightVectorGrid,"Text",getString(message('econ:econModeler:Import')),...
                "ButtonPushedFcn",@(s,e)this.importShortRun(s),'Tag','shortRunButton');
            this.ShortRunVectorButton.Layout.Row = 1;
            this.ShortRunVectorButton.Layout.Column = 3;
            this.ShortRunVectorTable = uitable(topRightVectorGrid,'Data',this.ShortRunVectorValues{1},...
                'RowName',{this.TimeSeries.Name},'ColumnName',{this.TimeSeries.Name},...
                'ColumnEditable',true,...
                'CellEditCallback',@this.setShortRun,'Tag','shortRunTable');
            this.ShortRunVectorTable.Layout.Row = 2;
            this.ShortRunVectorTable.Layout.Column = [1 4];

            bottomVectorGrid = uigridlayout(vectorGrid,[1 2],'ColumnWidth',{'1x','1x'},'Padding',[0,0,0,0]);
            bottomVectorGrid.Layout.Row = 2;

            bottomLeftVectorGrid = uigridlayout(bottomVectorGrid,[2,3],'RowHeight',{'fit','1x'},...
                'ColumnWidth',{'fit','fit','1x'});
            bottomLeftVectorGrid.Layout.Row = 1;
            bottomLeftVectorGrid.Layout.Column = 1;
            this.AdjustmentVectorLabel = uilabel(bottomLeftVectorGrid,'Text',[getString(message('econ:econModeler:AdjustmentSpeed')), ' (A)'],...
                'Interpreter','tex','Tag','adjustmentLabel');
            this.AdjustmentVectorLabel.Layout.Row = 1;
            this.AdjustmentVectorLabel.Layout.Column = 1;
            this.AdjustmentVectorButton = uibutton(bottomLeftVectorGrid,"Text",getString(message('econ:econModeler:Import')),...
                "ButtonPushedFcn",@(s,e)this.importAdjustment,'Tag','adjustmentButton');
            this.AdjustmentVectorButton.Layout.Row = 1;
            this.AdjustmentVectorButton.Layout.Column = 2;
            this.AdjustmentVectorTable = uitable(bottomLeftVectorGrid,'Data',nan(length(this.TimeSeries),this.RankOrderSpinner.Value),...
                'RowName',{this.TimeSeries.Name},...
                'ColumnEditable',true,'CellEditCallback',@this.setAdjustment,...
                'Tag','adjustmentTable');
            this.AdjustmentVectorTable.Layout.Row = 2;
            this.AdjustmentVectorTable.Layout.Column = [1 3];
            
            bottomRightVectorGrid = uigridlayout(bottomVectorGrid,[2,3],'RowHeight',{'fit','1x'},...
                'ColumnWidth',{'fit','fit','1x'});
            bottomRightVectorGrid.Layout.Row = 1;
            bottomRightVectorGrid.Layout.Column = 2;
            this.CointegrationVectorLabel = uilabel(bottomRightVectorGrid,'Text',[getString(message('econ:econModeler:CointegrationMatrix')), ' (B)'],...
                'Interpreter','tex','Tag','cointegrationLabel');
            this.CointegrationVectorLabel.Layout.Row = 1;
            this.CointegrationVectorLabel.Layout.Column = 1;
            this.CointegrationVectorButton = uibutton(bottomRightVectorGrid,"Text",getString(message('econ:econModeler:Import')),...
                "ButtonPushedFcn",@(s,e)this.importCointegration,'Tag','cointegrationButton');
            this.CointegrationVectorButton.Layout.Row = 1;
            this.CointegrationVectorButton.Layout.Column = 2;
            this.CointegrationVectorTable = uitable(bottomRightVectorGrid,'Data',nan(length(this.TimeSeries),this.RankOrderSpinner.Value),...
                'RowName',{this.TimeSeries.Name},...
                'ColumnEditable',true,'CellEditCallback',@this.setCointegration,...
                'Tag','cointegrationTable');
            this.CointegrationVectorTable.Layout.Row = 2;
            this.CointegrationVectorTable.Layout.Column = [1 3];

            %Create the Equation Axes
            this.ModelEqAxes = uiaxes(outergrid,...
                'XTick',[],...
                'XTickLabel',[],...
                'YTick',[],...
                'YTickLabel',[],...
                'XColor','white',...
                'YColor','white',...
                'Tag','modelEquationAxes');
            this.ModelEqAxes.Title.String = getString(message('econ:econModeler:ModelEquation'));
            this.ModelEqAxes.Layout.Row = 2;
            %Set this to avoid the axes toolbar from appearing
            this.ModelEqAxes.Toolbar.Visible = 'off';
            
            %Equation text
            this.ModelEqText = text(this.ModelEqAxes,0.5,0.5,'',...
                'Units','Normalized',...
                'FontSize',16,...
                'HorizontalAlignment','center',...
                'Interpreter','latex',...
                'Tag','modelEquationText');
            
            bottomgrid = uigridlayout(outergrid,[1 6],'ColumnWidth',{'1x','fit','fit','fit'});
            bottomgrid.Layout.Row = 3;
            
            %Details Button
            this.DetailsButton = uibutton(bottomgrid,...
                'Text',getString(message('econ:econModeler:Details')),...
                'ButtonPushedFcn',@this.launchHelp,...
                'Tag','detailsButton');
            this.DetailsButton.Layout.Column = 2;
            
            %Estimate Button
            this.EstimateButton = uibutton(bottomgrid,...
                'Text',getString(message('econ:econModeler:Estimate')),...
                'ButtonPushedFcn',@this.requestEstimate,...
                'Tag','estimateButton');
            this.EstimateButton.Layout.Column = 3;
            
            %Cancel Button
            this.CancelButton = uibutton(bottomgrid,...
                'Text',getString(message('econ:econModeler:Cancel')),...
                'ButtonPushedFcn',@this.closeFig,...
                'Tag','cancelButton');
            this.CancelButton.Layout.Column = 4;


            %Get the time series to estimate
            if isa(source,'internal.EconModeler.EconComponents.AbstractModel')
                this.FormOrderDropDown.Value = source.Form;

                %If the form was H1* or H* disable the cointegration matrix
                %controls
                if any(strcmpi(this.FormOrderDropDown.Value,["H1*","H*"]))
                    this.CointegrationOrderTable.Enable = 'off';
                    this.CointegrationVectorTable.Enable = 'off';
                    this.CointegrationOrderTable.Data = nan([size(this.CointegrationOrderTable.Data)]);
                    this.CointegrationVectorTable.Data = nan([size(this.CointegrationVectorTable.Data)]);
                    this.CointegrationOrderButton.Enable = 'off';
                    this.CointegrationVectorButton.Enable = 'off';
                end

                this.FormVectorDropDown.Value = source.Form;
                this.RankOrderSpinner.Value = source.Rank;
                this.RankVectorSpinner.Value = source.Rank;
                
                this.ShortRunOrderValues = source.ShortRunOrder;
                this.ShortRunVectorValues = source.ShortRunVector;
                this.LagOrderSpinner.Value = length(source.ShortRunOrder);
                srIdx = find(cellfun(@(x)~all(all(x==0)),source.ShortRunVector));
                this.LagVectorEdit.Value = num2str(srIdx);

                this.AdjustmentOrderTable.Data = source.Adjustment;
                this.AdjustmentVectorTable.Data = source.Adjustment;
                this.CointegrationOrderTable.Data = source.Cointegration;
                this.CointegrationVectorTable.Data = source.Cointegration;

                if source.Tab == "Order"
                    %Set the dialog to match the short run Order
                    this.TabGroup.SelectedTab = this.OrderTab;
                    this.setLags(this.LagOrderSpinner,struct(...
                        'Value',this.LagOrderSpinner.Value,'PreviousValue',1));
                else
                    %Set the dialog to match the custom short run Vector
                    this.TabGroup.SelectedTab = this.VectorTab;
                    this.checkVectorText(this.LagVectorEdit,struct('Value',this.LagVectorEdit.Value));
                end
            else
                this.setModelEquation();
            end

            movegui(this.Figure,'center');
            this.Figure.Visible = 'on';
            
            this.Listeners{end+1} = event.listener(this.Session,'AppClosed',@(s,e)closeCallback(this));
        end
    end

    methods(Access = protected)
        function closeCallback(this,~,~)
            this.Session.notify('DialogClosed');
            %Delete object when figure closes
            delete(this.Figure);
            delete(this);
        end
        
        function closeFig(this,~,~)
            %Cancel button and Estimate closes figure
            close(this.Figure);
        end

        function launchHelp(~,~,~)
            helpview('econ','vecm_refpg');
        end

        function setForm(this,~,e)
            this.FormOrderDropDown.Value = e.Value;
            this.FormVectorDropDown.Value = e.Value;
            
            enableCointegration = ~any(strcmpi(e.Value,["H1*","H*"]));
            wasCointegrationEnabled = ~any(strcmpi(e.PreviousValue,["H1*","H*"]));

            previousCointegration = this.CointegrationOrderTable.Data;

            if enableCointegration
                this.CointegrationOrderTable.Enable = 'on';
                this.CointegrationVectorTable.Enable = 'on';
                this.CointegrationOrderButton.Enable = 'on';
                this.CointegrationVectorButton.Enable = 'on';
            else
                this.CointegrationOrderTable.Enable = 'off';
                this.CointegrationVectorTable.Enable = 'off';
                this.CointegrationOrderTable.Data = nan([size(this.CointegrationOrderTable.Data)]);
                this.CointegrationVectorTable.Data = nan([size(this.CointegrationVectorTable.Data)]);
                this.CointegrationOrderButton.Enable = 'off';
                this.CointegrationVectorButton.Enable = 'off';
            end

            if wasCointegrationEnabled && ~enableCointegration
                %Store the cointegration matrix to use if the user switches
                %back to H2 H1 or H
                this.PreviousCointegrationMatrix = previousCointegration;
            end

            if enableCointegration && ~wasCointegrationEnabled
                [previousLength,previousWidth] = size(this.PreviousCointegrationMatrix);
                [~,currentWidth] = size(this.CointegrationOrderTable.Data);
                if previousWidth < currentWidth
                    %The rank has been increased, add extra columns
                    matrixToSet = [this.PreviousCointegrationMatrix,nan(previousLength,currentWidth-previousWidth)];
                elseif previousWidth > currentWidth
                    %The rank has been decreased, trim the extra columns
                    matrixToSet = this.PreviousCointegrationMatrix(:,1:currentWidth);
                else
                    matrixToSet = this.PreviousCointegrationMatrix;
                end

                this.CointegrationOrderTable.Data = matrixToSet;
                this.CointegrationOrderTable.Data = matrixToSet;
            end

            

            this.setModelEquation();
        end

        function setRank(this,~,e)
            rank = e.Value;
            this.RankOrderSpinner.Value = rank;
            this.RankVectorSpinner.Value = rank;

            %Modify Adjustment and Cointegration matrices accordingly
            [numRows,numCols] = size(this.AdjustmentOrderTable.Data);

            if rank < numCols
               this.AdjustmentOrderTable.Data(:,rank+1:end) = [];
               this.AdjustmentVectorTable.Data(:,rank+1:end) = [];
               this.CointegrationOrderTable.Data(:,rank+1:end) = [];
               this.CointegrationVectorTable.Data(:,rank+1:end) = [];
            elseif rank > numCols
                nansToAppend = nan(numRows,rank-numCols);
                this.AdjustmentOrderTable.Data = [this.AdjustmentOrderTable.Data,nansToAppend];
                this.AdjustmentVectorTable.Data = [this.AdjustmentVectorTable.Data,nansToAppend];
                this.CointegrationOrderTable.Data = [this.CointegrationOrderTable.Data,nansToAppend];
                this.CointegrationVectorTable.Data = [this.CointegrationVectorTable.Data,nansToAppend];
            end
        end

        function setLags(this,~,e)
            setModelEquation(this);

            order = e.Value;
            if order == 1
                this.LagVectorEdit.Value = "1";
            else
                this.LagVectorEdit.Value = "1:" + order;
            end
            this.checkVectorText(this.LagVectorEdit,struct('Value',this.LagVectorEdit.Value));

            oldOrder = e.PreviousValue;
            if oldOrder > order
                %Number of Lags has been reduced
                this.ShortRunOrderValues(order+1:end) = [];
                %Remove the higher orders from the parameters dropdown (order)
                if this.ShortRunOrderDropDown.Value > order
                    this.ShortRunOrderDropDown.Value = order;
                    this.updateTableDisplay();
                end
                this.ShortRunOrderDropDown.Items(order+1:end) = [];
                this.ShortRunOrderDropDown.ItemsData(order+1:end) = [];
            elseif order > oldOrder
                % Order is now larger, add items to the parameter dropdown 
                for n = oldOrder+1:order
                    this.ShortRunOrderValues(n) = {nan(length(this.TimeSeries))};
                    this.ShortRunOrderDropDown.Items{n} = getString(message('econ:econModeler:LagSelection',n));
                    this.ShortRunOrderDropDown.ItemsData(n) = n;
                end
            end

            %Set the values for the parameters dropdown vector
            this.ShortRunVectorDropDown.Items = {};
            this.ShortRunVectorDropDown.ItemsData = [];
            for n = 1:order
                this.ShortRunVectorDropDown.Items{n} = getString(message('econ:econModeler:LagSelection',n));
                this.ShortRunVectorDropDown.ItemsData(n) = n;
            end
            this.ShortRunVectorDropDown.Value = 1;
        end

        function checkVectorText(this,s,e)
        %Check edited text to confirm that it represents a MATLAB row
        %vector

            if isempty(e.Value)
                %Empty is valid
                s.FontColor = 'black';
                setModelEquation(this,[],[],s.Tag,e.Value);
                return;
            end

            numberExpression = '^[\d,:\[\]\s]*$';
            if isempty(regexp(e.Value,numberExpression,'once'))
                %Check to see only expected symbols in string
                s.FontColor = 'red';
                setModelEquation(this,[],[],s.Tag,e.Value);
                return;
            end

            try
                %Make sure expression evaluates to increasing integer row vector
                val = sort(str2num(e.Value)); %#ok<ST2NM>
                validateattributes(val,{'numeric'},{'integer','positive','row'});
                s.FontColor = 'black';
            catch
                s.FontColor = 'red';
            end 
            setModelEquation(this,[],[],s.Tag,e.Value);
            
            %Set the Dropdown items
            this.ShortRunVectorDropDown.Items = {};
            this.ShortRunVectorDropDown.ItemsData = [];
            for n = 1:length(val)
                this.ShortRunVectorDropDown.Items{n} = getString(message('econ:econModeler:LagSelection',val(n)));
                this.ShortRunVectorDropDown.ItemsData(n) = val(n);
            end

            for n = 1:max(val)
                if any(val == n)
                    if n > length(this.ShortRunVectorValues)
                        this.ShortRunVectorValues{n} = nan(length(this.TimeSeries));
                    end
                else
                    this.ShortRunVectorValues{n} = zeros(length(this.TimeSeries));
                end
            end
            if length(this.ShortRunVectorValues) > max(val)
                this.ShortRunVectorValues(max(val)+1:end) = [];
            end
        end

        function updateShortRunTable(this,~,~)
            this.ShortRunOrderTable.Data = this.ShortRunOrderValues{this.ShortRunOrderDropDown.Value};
            this.ShortRunVectorTable.Data = this.ShortRunVectorValues{this.ShortRunVectorDropDown.Value};
        end

        function setShortRun(this,~,~)
            this.ShortRunOrderValues{this.ShortRunOrderDropDown.Value} = this.ShortRunOrderTable.Data;
            this.ShortRunVectorValues{this.ShortRunVectorDropDown.Value} = this.ShortRunVectorTable.Data;
        end

        function setAdjustment(this,~,e)
            this.AdjustmentOrderTable.Data(e.Indices(1),e.Indices(2)) = e.NewData;
            this.AdjustmentVectorTable.Data(e.Indices(1),e.Indices(2)) = e.NewData;
        end

        function setCointegration(this,~,e)
            this.CointegrationOrderTable.Data(e.Indices(1),e.Indices(2)) = e.NewData;
            this.CointegrationVectorTable.Data(e.Indices(1),e.Indices(2)) = e.NewData;
        end

        function setModelEquation(this,~,~,varargin)

            p = inputParser;
            p.addParameter('lagEdit',[]);
            p.parse(varargin{:});

            equationString = this.getEquation(p.Results);
            if strcmp(equationString,getString(message('econ:econModeler:InvalidEquation')))
                %Do not use tex if displaying the invalid lag specification
                %message, as translation can produce warnings with tex
                this.ModelEqText.Interpreter = 'none';
            else
                this.ModelEqText.Interpreter = 'latex';
            end
            this.ModelEqText.String = equationString;
            drawnow; 
        end

        function str = getEquation(this,p)
            try
                str = "$$ \Delta y_{t} = ";
                str = str + this.getFormString() + this.getShortRunString(p) + "+ \varepsilon_{t}$$";
            catch
                %Display message if this fails
                str = getString(message('econ:econModeler:InvalidEquation'));
            end
        end

        function str = getFormString(this)
            form = this.FormOrderDropDown.Value;
            switch form
                case 'H2'
                    str = "AB'y_{t-1} ";
                case 'H1*'
                    str = "A(B'y_{t-1}+c_{0}) ";
                case 'H1'
                    str = "A(B'y_{t-1}+c_{0}) + c_{1} ";
                case 'H*'
                    str = "A(B'y_{t-1}+c_{0}+d_{0}t) + c_{1} ";
                case 'H'
                    str = "A(B'y_{t-1}+c_{0}+d_{0}t) + c_{1} + d_{1}t ";
            end
        end

        function str = getShortRunString(this,p)

            if this.TabGroup.SelectedTab == this.OrderTab
                order = this.LagOrderSpinner.Value;
                vector = 1:order;
            else
                if isempty(p.lagEdit)
                    vector = this.lagStr2Num(this.LagVectorEdit.Value);
                else
                    vector = this.lagStr2Num(p.lagEdit);
                end
            end

            if isempty(vector)
                str = "";
                return;
            end

            str = "+ ";
            if length(vector) >= 1 && length(vector) <= 3
                for n = vector
                    str = str + "\Phi_{" + n + "}\Delta y_{t-" + n + "}";
                    if n ~= vector(end)
                        str = str+"+";
                    end
                end
            elseif length(vector) > 3
                for n = 1:2
                    str = str + "\Phi_{" + vector(n) + "}\Delta y_{t-" + vector(n) + "}";
                    str = str+"+";
                end
                str = str + "...+\Phi_{" + vector(end) + "}\Delta y_{t-" + vector(end) + "}";
            end
        end

        function requestEstimate(this,~,~)
            import internal.EconModeler.EventData.NewModelEventData
            %Get all parameters, and notify app of estimate request

            params.TimeSeries = this.TimeSeries;
            if this.TabGroup.SelectedTab == this.OrderTab
                params.ShortRun = this.ShortRunOrderValues;
                params.Tab = "Order";
            else
                if strcmp(this.ModelEqText.String,getString(message('econ:econModeler:InvalidEquation')))
                    uialert(this.Figure,getString(message('econ:econModeler:InvalidLagSpecification')),...
                        getString(message('econ:econModeler:AppTitle')),'Modal',true,'Icon','error');
                    return;
                end
                params.ShortRun = this.ShortRunVectorValues;
                params.Tab = "Vector";
            end

            params.Form = this.FormOrderDropDown.Value;
            params.Rank = this.RankOrderSpinner.Value;
            params.Adjustment = this.AdjustmentOrderTable.Data;
            params.Cointegration = this.CointegrationOrderTable.Data;

            params.ShortRunOrder = this.ShortRunOrderValues;
            params.ShortRunVector = this.ShortRunVectorValues;

            this.FormOrderDropDown.Enable = 'off';
            rankEnabled = this.RankOrderSpinner.Enable;
            this.RankOrderSpinner.Enable = 'off';
            this.LagOrderSpinner.Enable = 'off';
            this.ShortRunOrderDropDown.Enable = 'off';
            this.ShortRunOrderTable.Enable = 'off';
            this.AdjustmentOrderTable.Enable = 'off';
            this.CointegrationOrderTable.Enable = 'off';
            this.FormVectorDropDown.Enable = 'off';
            this.RankVectorSpinner.Enable = 'off';
            this.LagVectorEdit.Enable = 'off';
            this.ShortRunVectorDropDown.Enable = 'off';
            this.ShortRunVectorTable.Enable = 'off';
            this.AdjustmentVectorTable.Enable = 'off';
            this.CointegrationVectorTable.Enable = 'off';
            this.DetailsButton.Enable = "off";
            this.EstimateButton.Enable = "off";
            this.CancelButton.Enable = "off";
            try
                this.Session.requestEstimate(NewModelEventData(this.ModelType,params));
            catch ME
                this.FormOrderDropDown.Enable = 'on';
                this.RankOrderSpinner.Enable = rankEnabled;
                this.LagOrderSpinner.Enable = 'on';
                this.ShortRunOrderDropDown.Enable = 'on';
                this.ShortRunOrderTable.Enable = 'on';
                this.AdjustmentOrderTable.Enable = 'on';
                this.CointegrationOrderTable.Enable = 'on';
                this.FormVectorDropDown.Enable = 'on';
                this.RankVectorSpinner.Enable = rankEnabled;
                this.LagVectorEdit.Enable = 'on';
                this.ShortRunVectorDropDown.Enable = 'on';
                this.ShortRunVectorTable.Enable = 'on';
                this.AdjustmentVectorTable.Enable = 'on';
                this.CointegrationVectorTable.Enable = 'on';
                this.DetailsButton.Enable = "on";
                this.EstimateButton.Enable = "on";
                this.CancelButton.Enable = "on";
                uialert(this.Figure,ME.message,...
                    getString(message('econ:econModeler:AppTitle')),...
                    'Icon','error','Modal',true);
                return;
            end
            this.closeFig();
        end

        function importAdjustment(this)
            %Filter base workspace variables that match the Adjustment
            %matrix size
            [numRows,numCols] = size(this.AdjustmentOrderTable.Data);
            allData = evalin('base','whos');
            validIdx = arrayfun(@(x)(strcmp('double',x.class) && length(x.size)==2  && x.size(1)== numRows && x.size(2) == numCols && ~x.complex),allData);
            validVariables = allData(validIdx);

            if isempty(validVariables)
                uialert(this.Figure,getString(message('econ:econModeler:AdjustmentImportNoValidVariables')),...
                        getString(message('econ:econModeler:AppTitle')),'Modal',true,'Icon','error');
            else
                validNames = {validVariables(:).name};
                [selectedIdx,anySelection] = listdlg('ListString',validNames,...
                    'PromptString',getString(message('econ:econModeler:AdjustmentImportPrompt')),...
                    'SelectionMode','single',...
                    'Name',getString(message('econ:econModeler:AppTitle')),...
                    'ListSize',[250 100]);
                if anySelection
                    selectedVariableName = validNames{selectedIdx};
                    this.AdjustmentOrderTable.Data = evalin('base',selectedVariableName);
                    this.AdjustmentVectorTable.Data = this.AdjustmentOrderTable.Data;
                end
            end
        end

        function importCointegration(this)
            %Filter base workspace variables that match the Cointegration
            %matrix size
            [numRows,numCols] = size(this.CointegrationOrderTable.Data);
            allData = evalin('base','whos');
            validIdx = arrayfun(@(x)(strcmp('double',x.class) && length(x.size)==2  && x.size(1)== numRows && x.size(2) == numCols && ~x.complex),allData);
            validVariables = allData(validIdx);

            if isempty(validVariables)
                uialert(this.Figure,getString(message('econ:econModeler:CointegrationImportNoValidVariables')),...
                        getString(message('econ:econModeler:AppTitle')),'Modal',true,'Icon','error');
            else
                validNames = {validVariables(:).name};
                [selectedIdx,anySelection] = listdlg('ListString',validNames,...
                    'PromptString',getString(message('econ:econModeler:CointegrationImportPrompt')),...
                    'SelectionMode','single',...
                    'Name',getString(message('econ:econModeler:AppTitle')),...
                    'ListSize',[250 100]);
                if anySelection
                    selectedVariableName = validNames{selectedIdx};
                    this.CointegrationOrderTable.Data = evalin('base',selectedVariableName);
                    this.CointegrationVectorTable.Data = this.CointegrationOrderTable.Data;
                end
            end
        end

        function importShortRun(this,s)
            [numRows,numCols] = size(this.ShortRunOrderTable.Data);
            allData = evalin('base','whos');
            validIdx = arrayfun(@(x)(strcmp('double',x.class) && length(x.size)==2  && x.size(1)== numRows && x.size(2) == numCols && ~x.complex),allData);
            validVariables = allData(validIdx);

            if isempty(validVariables)
                uialert(this.Figure,getString(message('econ:econModeler:ShortRunImportNoValidVariables')),...
                        getString(message('econ:econModeler:AppTitle')),'Modal',true,'Icon','error');
            else
                validNames = {validVariables(:).name};
                [selectedIdx,anySelection] = listdlg('ListString',validNames,...
                    'PromptString',getString(message('econ:econModeler:ShortRunImportPrompt')),...
                    'SelectionMode','single',...
                    'Name',getString(message('econ:econModeler:AppTitle')),...
                    'ListSize',[250 100]);
                if anySelection
                    selectedVariableName = validNames{selectedIdx};
                    if s == this.ShortRunOrderButton
                        this.ShortRunOrderTable.Data = evalin('base',selectedVariableName);
                    else
                        this.ShortRunVectorTable.Data = evalin('base',selectedVariableName);
                    end
                    this.setShortRun();
                end
            end
        end
    end

    methods(Static)
        function num = lagStr2Num(str)
            %Convert a lag vector string to number equivalent
            
            if isempty(str)
                num = [];
                return;
            end
            
             numberExpression = '^[\d,:\[\]\s]*$';
             if isempty(regexp(str,numberExpression,'once'))
                 error(message('econ:econModeler:InvalidLagSpecification'));
             end
           
             num = str2num(str); %#ok<ST2NM>
             validateattributes(num,{'numeric'},{'integer','positive','row'});
        end
    end
end

