function [plotHandles,annotationHandles] = visualizeAICoverNumberOfInputs(obj,axesHandle,numberOfLines,plotOptionObject,figureHandle)
% This function creates a plot where the achieved loss function value over
% different numbers of inputs is displayed. axesHandle is an optional
% input, if you want to pass the plot to a certain axes.

%%
% clc

if ~exist('plotOptionObject','var') || isempty(plotOptionObject)
%     plotOptionObject = PlotOptions;
end

% Defining plot options
% fontName = plotOptionObject.fontname;
% fontSize = plotOptionObject.fontsize;
% linewidth = plotOptionObject.linewidth;
% markersize = plotOptionObject.markersize;
[fontName,fontSize,linewidth] = sensitivityAnalysis.getPlotOptions;%'Arial';
markersize = 10;

% Calculate the number of inputs for every line within the combination
% matrix
numberOfInputs = sum(obj.combinationMatrix,2);

% Determine the maximum number of inputs used
maxNumberOfInputs = max(numberOfInputs);
minNumberOfInputs = min(numberOfInputs);

% If the minimum number of inputs is zero, the previously determined
% maximum number of inputs is not equal to the number of different inputs,
% which are needed for the x-axis designation
maxNumberOfDifferentInputs = size(minNumberOfInputs:maxNumberOfInputs,2);

% Evaluate the maximum number of combinations for every number of inputs
% and save the highest number of combinations through all numbers of inputs
maxNumberOfCombinations = 0;
for ii=minNumberOfInputs:maxNumberOfInputs
    tmp = sum(numberOfInputs==ii);
    if tmp > maxNumberOfCombinations
        maxNumberOfCombinations = tmp;
    end
end

% Predefine a matrix, where the colum number corresponds to the number of
% inputs and in each line there are the lossFunction/AIC values, which are
% sorted in ascending order
lossFunctionMatrix = NaN(maxNumberOfCombinations, maxNumberOfDifferentInputs);

% Predefine a cell-array of the same size as the lossFunctionMatrix. Every
% entry in this cell array contains the name of the input, that has been
% added in the corresponding field of the lossFunctionMatrix
addedInput = cell(maxNumberOfCombinations, maxNumberOfDifferentInputs);

% Fill lossFunctionMatrix and sort every colum on its own
for ii=0:maxNumberOfInputs
    % Determine the indices of all number of inputs of the current loop
    % cycle
    idx = numberOfInputs == ii;
    
    % idx might be empty, if the number of fixed inputs is greater than one
    if ~isempty(idx)
        
        % Fill the corresponding colum of the lossFunctionMatrix
        numberOfHits = sum(idx);
        lossFunctionMatrix(1:numberOfHits,ii+1) = obj.sensitivityResults.lossFunctionValue(idx);
        
        % Save corresponding input combinations
        addedInput(1:numberOfHits,ii+1) = mat2cell(obj.combinationMatrix(idx,:),ones(1,numberOfHits),size(obj.combinationMatrix,2));
        
        % Sort the colums in ascending order
        [lossFunctionMatrix(1:numberOfHits,ii+1),indices] = sort(lossFunctionMatrix(1:numberOfHits,ii+1));
        addedInput(1:numberOfHits,ii+1) = addedInput(indices,ii+1);
        
    end
    
end

if strcmp(obj.strategy,'bruteForce')
    % Describe the points of the curves within the legend
    
    % Predefine cell array, that can later be used to define the legend of
    % the plot
    legendDescription = cell(1,maxNumberOfCombinations);
    
    % Loop over all curves, that will be plotted
    for ii=1:maxNumberOfCombinations
        
        % Predefine string in corresponding legend description
        legendDescription{1,ii} = '';
        
        % Loop over all potential points of one single curve
        for kk=0:maxNumberOfInputs
            
            % Check if for the current number of inputs there is an
            % combination vector
            if ~isempty(addedInput{ii,kk+1})
                
                % Check if there was no input used
                loopVariable = find(addedInput{ii,kk+1});
                if isempty(loopVariable)
                    legendDescription{1,ii} = [legendDescription{1,ii},'[]'];
                end
                
                % Add the name of every included input
                for jj=loopVariable
                    
                    if jj==find(addedInput{ii,kk+1},1,'first')
                        legendDescription{1,ii} = [legendDescription{1,ii},'['];
                    end
                    
                    legendDescription{1,ii} = [legendDescription{1,ii},obj.info.inputDescription{1,jj}];
                    if jj~=find(addedInput{ii,kk+1},1,'last')
                        legendDescription{1,ii} = [legendDescription{1,ii},';'];
                    else
                        % At the end of one input combination
                        legendDescription{1,ii} = [legendDescription{1,ii},'] '];
                    end
                    
                end
                
            end
            
        end
    end
    
else
    % Description of the points in the plot, if the method used for
    % evaluating good input combinations is not the brute force
    % strategy
    
    % Predefine vector, where no input (colum of the original data matrix)
    % ist selected (only zeros)
    justAdded = zeros(1,size(obj.combinationMatrix,2));
    
    % Predefine cell array that will contain the name of the added input.
    names = cell(1,maxNumberOfDifferentInputs);
    
    % Determine the names of the added inputs
    for ii=minNumberOfInputs:maxNumberOfInputs
        
        % Because the justAdded vector is initialized with only zeros it is
        % sufficient to search for occuring ones after adding an input
        % combination vector. In further steps ones will occur only at
        % colums, where there were nothing before, all other colums are
        % greater than one or zero
        justAdded = justAdded + addedInput{1,ii+1};
        idx = justAdded == 1;
        
        % Initialize the string entry in the names cell
        names{1,ii+1} = '';
        
        % The case where idx contains more than one entry that differs from
        % zero can only occur in the first cycle of the loop, if the user
        % demanded a number of fixed inputs greater than one
        for jj=find(idx)
            
            % Name the added input as it is named in the input description
            % property
            names{1,ii+1} = [names{1,ii+1},obj.info.inputDescription{1,jj}];
            
            % Add a semicolon at the end of the name, if there are further
            % inputs, that were added in the same step
            if jj~=find(idx,1,'last')
                names{1,ii+1} = [names{1,ii+1},'; '];
            end
            
        end
        
    end
    
end

% Create plot
if exist('axesHandle','var') && ~isempty(axesHandle)
    %     fh = gcf;
    if ~exist('figureHandle','var') || isempty(figureHandle)
        fh = gcf;
    else
        fh = figureHandle;
    end
    ah = axesHandle;
else
    fh = figure;
    ah = axes;
    set(fh,'CurrentAxes',ah);
end
hold(ah,'on');
grid(ah,'on');

% Define vector containing all numbers of inputs
numberOfInputVariables = 0:maxNumberOfInputs;

% Initialize variables that will contain the maximum and minimum value of
% all lossFunction values
minLoss = inf;
maxLoss = -inf;

% If the variable numberOfLines is passed to this function
if exist('numberOfLines','var') && ~isempty(numberOfLines)
    maxNumberOfCombinations = numberOfLines;
else
    maxNumberOfCombinations = 1:maxNumberOfCombinations;
end

% Variable for cycle counting
helpMeCount = 1;

% Cell array containing all handles to the plot lines
plotHandles = cell(size(maxNumberOfCombinations,2),1);

for ii=maxNumberOfCombinations
    
    % Plotting
    plotHandles{helpMeCount,1}=plot(ah,numberOfInputVariables,lossFunctionMatrix(ii,:),...
        'Color',rand(1,3),'LineWidth',linewidth,'Marker','o','MarkerSize',markersize,'LineStyle',':');
    
    % If there are names, add them near the corresponding point in the plot
    if exist('names','var')
        annotationHandles = cell(1,size(lossFunctionMatrix(ii,:),2));
        
        % Go through all lossFunction values of the current cycle and add
        % textbox if the current entry is no nan-value
        for kk=1:size(lossFunctionMatrix(ii,:),2)
            if ~isnan(lossFunctionMatrix(ii,kk))
                
                % Determine text position
                xPosition = numberOfInputVariables(kk)+0.15;
                yPosition = lossFunctionMatrix(ii,kk)+0.015;
                
                %
                set(fh,'CurrentAxes',ah);
                figure(fh);
                
                % Create textbox
                annotationHandles{kk} = text(xPosition,yPosition,names{1,kk});
                
                % Format contained text
                set(annotationHandles{kk},'FontName',fontName,'FontSize',fontSize);
                
            end
        end
        
    end
    
    % Update minimum and maximum values of the loss function
    if min(lossFunctionMatrix(ii,:)) < minLoss
        minLoss = min(lossFunctionMatrix(ii,:));
    end
    if max(lossFunctionMatrix(ii,:)) > maxLoss
        maxLoss = max(lossFunctionMatrix(ii,:));
    end
    
    % Increase cycle counter
    helpMeCount = helpMeCount + 1;
    
end

if exist('legendDescription','var')
    hl = legend(ah,legendDescription(1,maxNumberOfCombinations));
    set(hl,'FontName',fontName,'FontSize',fontSize);
end

if ~exist('annotationHandles','var')
    annotationHandles = [];
end

% Determine the range of the loss function values
rangeLoss = maxLoss - minLoss;

% Change appearance of the plot
set(ah,'XLim',[minNumberOfInputs-1 maxNumberOfInputs+1],...
    'XTick',minNumberOfInputs-1:maxNumberOfInputs+1,...
    'Box','on')
minYvalue = minLoss-0.08*rangeLoss;
maxYvalue = maxLoss+0.08*rangeLoss;
if maxYvalue-minYvalue > eps
    set(ah,'YLim',[minYvalue maxYvalue]);
end
hx = xlabel(ah,'Number of Inputs');
hy = ylabel(ah,'AIC');
set([ah,hx,hy],'FontName',fontName,'FontSize',fontSize)

end