function stop = anfisOutputFcn(info,varargin)
%%

%  Copyright 2022-2023 The MathWorks, Inc.

persistent sinks startPlot stopValue

if isempty(startPlot)
    startPlot = false;
end

if isempty(stopValue)
    stopValue = false;
end

msg = '';
x = [];
y = [];

if ~isempty(varargin)
    sinks = varargin{1};
end

if ~isempty(sinks) && stopValue~=sinks.Stop
    stopValue = sinks.Stop;
end

stop = stopValue;

if isempty(info)
    return
end

switch info.State
    case fuzzy.anfis.internal.ANFISState.StopMessage
        msg = stopMessage();
    case fuzzy.anfis.internal.ANFISState.ParameterInfoMessage
        msg = parameterInfoMessage(info);
    case fuzzy.anfis.internal.ANFISState.TrainingStartMessage
        msg = trainingStartMessage(info);
        startPlot = true;
    case fuzzy.anfis.internal.ANFISState.DisplayErrorMessage
        msg = displayErrorMessage(info);
        x = info.IterationNumber;
        y = info.TrainingError;
    case fuzzy.anfis.internal.ANFISState.ErrorGoalReachedMessage
        msg = errorGoalReachedMessage(info);
    case fuzzy.anfis.internal.ANFISState.EpochGoalReachedMessage
        msg = epochGoalReachedMessage(info);
    case fuzzy.anfis.internal.ANFISState.MinimumErrorMessage
        msg = minimumErrorMessage(info);
    case fuzzy.anfis.internal.ANFISState.StepSizeIncreasedMessage
        msg = stepSizeIncreasedMessage(info);
    case fuzzy.anfis.internal.ANFISState.StepSizeDecreasedMessage
        msg = stepSizeDecreasedMessage(info);
end

if isempty(sinks) && ~isempty(msg)
    fprintf(msg)
    return
end

if ~isempty(x)
    lg = sinks.PlotDocument.Legends; 
    setLegends = startPlot && (info.NumberOfCheckingPairs>0); %&& ~lg.Visible;
    if setLegends
        lg.Visible = 'on';
        lg.AutoUpdate = 'on';
        startPlot = false;
    end

    % if ~isempty(sinks.PreIteration)
        X = [sinks.PreIteration x];
        sinks.PreIteration = x;
        Y = [sinks.PreTrainingCost y];
        sinks.PreTrainingCost = y;
    % end
    
    ax = sinks.PlotDocument.Axes;
    ax.ColorOrderIndex = 1;
    hold(ax,'on')
    plot(ax,X,Y, ...
        'LineStyle',sinks.PlotDocument.TrainingLineStyle, ...
        'Marker',sinks.PlotDocument.TrainingMarker)
    if info.NumberOfCheckingPairs>0
        Y = [sinks.PreValidationCost info.CheckingError];
        sinks.PreValidationCost = info.CheckingError;

        plot(ax,X,Y, ...
            'LineStyle',sinks.PlotDocument.ValidationLineStyle, ...
            'Marker',sinks.PlotDocument.ValidationMarker)
    end

    hold(ax,'off')    
    if setLegends
        lg.AutoUpdate = 'off';
        lg.String = sinks.PlotDocument.LegendLabels;
    end

    pause(0.075)
end

if ~isempty(msg)
    msg(end) = [];
    txt = sinks.ResultsDocument.Text;
    txt.Value = [txt.Value;msg];
    txt.scroll('bottom')
end

end
%% Local functions
function msg = parameterInfoMessage(info)
%%
persistent infoTitle numNodes numLinParams numNonlinParams totalNumParams ...
    numTrainingPairs numCheckingPairs numFuzzyRules
if isempty(infoTitle)
    infoTitle = getString(message('fuzzy:general:msgAnfisMex_infoTitle'));
    numNodes = getString(message('fuzzy:general:msgAnfisMex_NumberOfNodes'));
    numLinParams = getString(message('fuzzy:general:msgAnfisMex_NumberOfLinearParams'));
    numNonlinParams = getString(message('fuzzy:general:msgAnfisMex_NumberOfNonlinearParams'));
    totalNumParams = getString(message('fuzzy:general:msgAnfisMex_TotalNumberOfParams'));
    numTrainingPairs = getString(message('fuzzy:general:msgAnfisMex_NumberOfTrainingPairs'));
    numCheckingPairs = getString(message('fuzzy:general:msgAnfisMex_NumberOfCheckingPairs'));
    numFuzzyRules = getString(message('fuzzy:general:msgAnfisMex_NumberOfFuzzyRules'));
end
msg = sprintf('\n%s\n',infoTitle);
msg = sprintf([msg '\t' numNodes '\n'],info.NumberOfNodes);
msg = sprintf([msg '\t' numLinParams '\n'],info.NumberOfLinearParams);
msg = sprintf([msg '\t' numNonlinParams '\n'],info.NumberOfNonlinearParams);
msg = sprintf([msg '\t' totalNumParams '\n'],info.TotalNumberOfParams);
msg = sprintf([msg '\t' numTrainingPairs '\n'],info.NumberOfTrainingPairs);
msg = sprintf([msg '\t' numCheckingPairs '\n'],info.NumberOfCheckingPairs);
msg = sprintf([msg '\t' numFuzzyRules '\n\n'],info.NumberOfFuzzyRules);
end

function msg = trainingStartMessage(info)
%%
persistent epochLabel trainingLabel validationLabel errorLabel
if isempty(epochLabel)
    epochLabel = getString(message('fuzzy:dialogs:lblEpoch'));
    trainingLabel = getString(message('fuzzy:dialogs:lblTraining'));
    validationLabel = getString(message('fuzzy:dialogs:lblValidation'));
    errorLabel = getString(message('fuzzy:dialogs:lblError'));
end
msg = sprintf('\n%s\n\n',getString(message('fuzzy:general:msgAnfisMex_trainingStart')));
if info.NumberOfCheckingPairs==0
    msg = sprintf('%s\t%s\t\t%s\n\t\t\t\t%8s\n', ...
        msg,epochLabel,trainingLabel,errorLabel);
else
    msg = sprintf('%s\t%s\t\t%s\t\t%s\n\t\t\t\t%8s\t\t%8s\n', ...
        msg,epochLabel,trainingLabel,validationLabel,errorLabel,errorLabel);
end
end

function msg = displayErrorMessage(info)
%%
if (info.NumberOfCheckingPairs ~= 0)
    msg = sprintf('%12d\t\t%15.6g\t%16.6g\n',info.IterationNumber, ...
        info.TrainingError,info.CheckingError);
else
    msg = sprintf('%12d\t\t%15.6g\n',info.IterationNumber, ...
        info.TrainingError);
end
end

function msg = errorGoalReachedMessage(info)
%%
persistent format
if isempty(format)
    format = getString(message('fuzzy:general:msgAnfisMex_errorGoalReached'));
end
msg = sprintf(['\n' format '\n\n'],info.TrainingErrorGoal,info.ActualEpochNumber);
end

function msg = epochGoalReachedMessage(info)
%%
persistent format
if isempty(format)
    format = getString(message('fuzzy:general:msgAnfisMex_epochReached'));
end
msg = sprintf(['\n' format '\n\n'],info.EpochNumberGoal);
end

function msg = minimumErrorMessage(info)
%%
persistent trnErrFormat vldErrFormat
if isempty(trnErrFormat)
    trnErrFormat = getString(message('fuzzy:general:msgAnfisMex_minTrnErrDispFormat'));
    vldErrFormat = getString(message('fuzzy:dialogs:msgMinValidationRMSEFormat'));
end
msg = sprintf([trnErrFormat '\n'],info.MinimumTrainingError);
if (info.NumberOfCheckingPairs ~= 0)
    msg = sprintf([msg vldErrFormat '\n'],info.MinimumCheckingError);
end
end

function msg = stepSizeIncreasedMessage(info)
%%
persistent format
if isempty(format)
    format = getString(message('fuzzy:general:msgAnfisMex_stepSizeDecrease'));
end
msg = sprintf([format '\n'],info.StepSize,info.IterationNumber);
end

function msg = stepSizeDecreasedMessage(info)
%%
persistent format
if isempty(format)
    format = getString(message('fuzzy:general:msgAnfisMex_stepSizeIncrease'));
end
msg = sprintf([format '\n'],info.StepSize,info.IterationNumber);
end

function msg = stopMessage
%%
persistent optTerminated stopRequested
if isempty(optTerminated)
    optTerminated = getString(message('fuzzy:dialogs:msgOptimizationTerminated'));
    stopRequested = getString(message('fuzzy:dialogs:msgTuning_stopedByUser'));
end
msg = sprintf(['\n' optTerminated ': ' stopRequested '\n\n']);
end