classdef (Hidden,Sealed)UIVARXParameterDialog < internal.EconModeler.Dialogs.UIVARParameterDialog
    %UIVARXPARAMETERDIALOG Dialog for setting VARX Model Parameters
    
    %Copyright 2021 The MathWorks Inc.
    
    properties(Access = protected)
        PredictorPanel matlab.ui.container.Panel
        PredictorTable matlab.ui.control.Table

    end
    
    methods (Access = ?internal.EconModeler.DialogFactory)
        function this = UIVARXParameterDialog(session,source)

            if isa(source,'internal.EconModeler.EconComponents.AbstractTimeSeries')
                allTS = session.getAllTimeSeries();
                if length(source)==length(allTS)
                    error(message('econ:econModeler:VARXAllTSSelected'));
                end
            end

            this = this@internal.EconModeler.Dialogs.UIVARParameterDialog(session,source);

            this.Figure.Name = getString(message('econ:econModeler:VARXModelTitle'));

            if isa(source,'internal.EconModeler.EconComponents.AbstractModel')
                this.TimeSeries = source.Parent(1:source.NumSeries);
            end

            this.ModelType = internal.EconModeler.Enumerations.ModelTypes.VARX;

            outerGrid = findobj(this.Figure.Children,'flat','Type','uigridlayout');
            outerGrid.ColumnWidth = {'1x','fit'};


            this.PredictorPanel = uipanel(outerGrid,...
                'FontWeight','bold',...
                'Title',getString(message('econ:econModeler:Predictors')),...
                'TitlePosition','centertop',...
                'Tag','predictorPanel');
            this.PredictorPanel.Layout.Row = 1;
            this.PredictorPanel.Layout.Column = 2;
            
            predictorGrid = uigridlayout(this.PredictorPanel,[1 1],'RowHeight',{'1x'});
            
            %Predictor Table
            this.PredictorTable= uitable(predictorGrid,...
                'ColumnName',{getString(message('econ:econModeler:Include')),...
                getString(message('econ:econModeler:TSWorkspaceName'))},...
                'RowName',[],...
                'ColumnFormat',{'logical','char'},...
                'ColumnEditable',[true,false],...
                'CellEditCallback',@this.setModelEquation,...
                'Tag','predictorTable');

            %Fill the predictor list with all time series other than the
            %selected ones
            allTS = this.Session.getAllTimeSeries();
            selectedTS = this.TimeSeries;
            tsToSelect = internal.EconModeler.EconComponents.AbstractTimeSeries.empty;
            for n = 1:length(allTS)
                if ~any(allTS(n) == selectedTS)
                    tsToSelect(end+1) = allTS(n); %#ok<AGROW> 
                end
            end

            this.PredictorTable.Data = [num2cell(false(length(tsToSelect),1)),{tsToSelect(:).Name}'];

            if isa(source,'internal.EconModeler.EconComponents.AbstractModel')
                predictors = {source.Parent(source.NumSeries+1:end).Name};
                [~,indicesToSelect] = intersect(this.PredictorTable.Data(:,2),predictors);
                this.PredictorTable.Data(indicesToSelect,1) = {true};
            end

            this.ModelEqAxes.Layout.Column = [1 2];
            bottomGrid = findobj(outerGrid.Children,'flat','Type','uigridlayout');
            bottomGrid.Layout.Column = [1 2];

            setModelEquation(this);
        end
    end

    methods(Access = protected)

        function width = getWidth(~)
            width = 1050;
        end

        function str = getEquation(this,p)
            try
                %Build ARIMA equation
                str = "y_{t} = ";
                str = "$$" + this.getARString(p) + str + ...
                    this.getConstantString() + this.getTrendString() + ...
                    this.getPredictorString() + "\varepsilon_{t}$$";
            catch
                %Display message if this fails
                str = getString(message('econ:econModeler:InvalidEquation'));
            end
        end

        function str = getPredictorString(this)
            %Produce predictor part of equation
            if ~isempty(this.PredictorTable.Data)
                predictors = this.PredictorTable.Data([this.PredictorTable.Data{:,1}],2);
            else
                predictors = [];
            end
            
            if isempty(predictors)
                str = "";
            elseif length(predictors) < 4
                str = "";
                for n = 1:length(predictors)
                    str = str + "X_{" + num2str(n) + "}\beta_{" + num2str(n) + "}+";
                end
            else
                str = "X_{1}\beta_{1}+...+X_{" + num2str(length(predictors)) + "}\beta_{" + num2str(length(predictors)) + "}+";
            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.AR = this.AROrderValues;
            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.AR = this.ARVectorValues;
            end
            if this.ConstantOrderCheckBox.Value
                params.Constant = nan(length(this.TimeSeries),1);
            else
                params.Constant = zeros(length(this.TimeSeries),1);
            end
            if this.TrendOrderCheckBox.Value
                params.Trend = nan(length(this.TimeSeries),1);
            else
                params.Trend = zeros(length(this.TimeSeries),1);
            end

            if ~isempty(this.PredictorTable.Data)
                params.Exogenous = this.PredictorTable.Data([this.PredictorTable.Data{:,1}],2);
            else
                params.Exogenous = [];
            end

            if this.TabGroup.SelectedTab == this.OrderTab
                params.Tab = 'Order';
            else
                params.Tab = 'Vector';
            end

            params.AROrder = this.AROrderValues;
            params.ARVector = this.ARVectorValues;
            
            this.AROrderSpinner.Enable = "off";
            this.ConstantOrderCheckBox.Enable = "off";
            this.TrendOrderCheckBox.Enable = "off";
            this.ParametersOrderDropDown.Enable = "off";
            this.ParametersOrderTable.Enable = "off";
            this.ARVectorEdit.Enable = "off";
            this.ConstantVectorCheckBox.Enable = "off";
            this.TrendVectorCheckBox.Enable = "off";
            this.ParametersVectorDropDown.Enable = "off";
            this.ParametersVectorTable.Enable = "off";
            this.PredictorTable.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.AROrderSpinner.Enable = "on";
                this.ConstantOrderCheckBox.Enable = "on";
                this.TrendOrderCheckBox.Enable = "on";
                this.ParametersOrderDropDown.Enable = "on";
                this.ParametersOrderTable.Enable = "on";
                this.ARVectorEdit.Enable = "on";
                this.ConstantVectorCheckBox.Enable = "on";
                this.TrendVectorCheckBox.Enable = "on";
                this.ParametersVectorDropDown.Enable = "on";
                this.ParametersVectorTable.Enable = "on";
                this.PredictorTable.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
    end
end

