function netPreds = directAssessment(inputData, Fs)
x = zeros(length(inputData),1);
x(:,1) = inputData;

[xStoreTest,yStoreTest,intFactor,decFactor,err] = loadData(x,Fs);
if err == 1
   netPreds = [];
   return
end   

load trainVars4.mat miniBatchSize parameters hyperparameters classes

dsXTest = arrayDatastore(xStoreTest,'OutputType','same');
dsYTest = arrayDatastore(yStoreTest,'OutputType','same');

dsTest = combine(dsXTest,dsYTest);

mbqTest = minibatchqueue(dsTest,3,...
    'MiniBatchSize',miniBatchSize,...
    'MiniBatchFcn', @preprocessMiniBatch);

doTraining = false;

predictions = [];
predCorr = [];

while hasdata(mbqTest)
    [dlXTest,dlYTest] = next(mbqTest);
        
    dlYPred = model(dlXTest,parameters,hyperparameters,doTraining);
    dlYPred = softmax(dlYPred,'DataFormat','CBT');    
    
    YPred = onehotdecode(dlYPred,classes,1);
    YTest = onehotdecode(dlYTest,classes,1);
    
    predictions = [predictions YPred];  
end

A = squeeze(predictions);
if min(size(A)) == 1
   A = transpose(A);
end

netPreds = [];
for i = 1:height(A)-1
    B = A(i,:);
    netPreds = [netPreds,B];
end 
B = A(height(A),:);
netPreds = [netPreds,B(1:length(xStoreTest{end}))];

Qwindow = 50;
m = numel(netPreds);
netPreds = double(transpose(netPreds));
QCell = mat2cell(netPreds,diff([0:Qwindow:m-1,m]));

% Výpočet procentuálního zastoupení známek v daném okně 
for i = 1:length(QCell)
    Qinput = double(QCell{i});
    QinputLen = length(Qinput);
    oneQper = (length(Qinput(Qinput == 1))/QinputLen)*100;
    twoQper = (length(Qinput(Qinput == 2))/QinputLen)*100;
    threeQper = (length(Qinput(Qinput == 3))/QinputLen)*100;
    qPercentage = [oneQper,twoQper,threeQper];
    % Pokud je v okně převažující známka 3, označ celé ono jako 3
    if max(qPercentage) == oneQper
       netPreds(i*Qwindow-Qwindow+1:i*Qwindow-Qwindow+QinputLen) = 1;
    end
    if max(qPercentage) == twoQper
       netPreds(i*Qwindow-Qwindow+1:i*Qwindow-Qwindow+QinputLen) = 2;
    end
    if max(qPercentage) == threeQper
       netPreds(i*Qwindow-Qwindow+1:i*Qwindow-Qwindow+QinputLen) = 3;
    end    
end

oneQ = (length(netPreds(netPreds == 1))/length(netPreds))*100;
twoQ = (length(netPreds(netPreds == 2))/length(netPreds))*100;
threeQ = (length(netPreds(netPreds == 3))/length(netPreds))*100;
qPercentage = [oneQ,twoQ,threeQ];

netPreds = double(netPreds);
netPreds = interp(netPreds, decFactor);
netPreds = round(netPreds);
netPreds = downsample(netPreds, intFactor);
netPreds = netPreds(1:length(inputData));
end

function dlY = model(dlX,parameters,hyperparameters,doTraining)

numBlocks = hyperparameters.NumBlocks;
dropoutFactor = hyperparameters.DropoutFactor;

dlY = dlX;

% Residual blocks.
for k = 1:numBlocks
    dilationFactor = 2^(k-1);
    parametersBlock = parameters.("Block"+k);
    
    dlY = residualBlock(dlY,dilationFactor,dropoutFactor,parametersBlock,doTraining);
end

% Fully connect
weights = parameters.FC.Weights;
bias = parameters.FC.Bias;
dlY = fullyconnect(dlY,weights,bias,'DataFormat','CBT');

end

function dlY = residualBlock(dlX,dilationFactor,dropoutFactor,parametersBlock,doTraining)

% Convolution options.
filterSize = size(parametersBlock.Conv1.Weights,1);
paddingSize = (filterSize - 1) * dilationFactor;

% Convolution.
weights = parametersBlock.Conv1.Weights;
bias =  parametersBlock.Conv1.Bias;
dlY = dlconv(dlX,weights,bias, ...
    'DataFormat','CBS', ...
    'Stride', 1, ...
    'DilationFactor', dilationFactor, ...
    'Padding', [paddingSize; 0] );

% Instance normalization, ReLU, spatial dropout.
dlY = instanceNormalization(dlY,'CBS');
dlY = relu(dlY);
dlY = spatialDropout(dlY,dropoutFactor,'CBS',doTraining);

% Convolution.
weights = parametersBlock.Conv2.Weights;
bias = parametersBlock.Conv2.Bias;
dlY = dlconv(dlY,weights,bias, ...
    'DataFormat','CBS', ...
    'Stride', 1, ...
    'DilationFactor', dilationFactor, ...
    'Padding',[paddingSize; 0] );

% Instance normalization, ReLU, spatial dropout.
dlY = instanceNormalization(dlY,'CBS');
dlY = relu(dlY);
dlY = spatialDropout(dlY,dropoutFactor,'CBS',doTraining);

% Optional 1-by-1 convolution.
if ~isequal(size(dlX),size(dlY))
    weights = parametersBlock.Conv3.Weights;
    bias = parametersBlock.Conv3.Bias;
    dlX = dlconv(dlX,weights,bias,'DataFormat','CBS');
end

% Addition and ReLU
dlY = relu(dlX+dlY);

end




function dlY = instanceNormalization(dlX,fmt)

reductionDims = find(fmt == 'S');
mu = mean(dlX,reductionDims);
sigmaSq = var(dlX,1,reductionDims);

epsilon = 1e-5;
dlY = (dlX-mu) ./ sqrt(sigmaSq+epsilon);

end

function dlY = spatialDropout(dlX,dropoutFactor,fmt,doTraining)

if doTraining
    maskSize = size(dlX);
    maskSize(fmt=='S') = 1;
    
    dropoutScaleFactor = single(1 - dropoutFactor);
    dropoutMask = (rand(maskSize,'like',dlX) > dropoutFactor) / dropoutScaleFactor;
    
    dlY = dlX .* dropoutMask;
else
    dlY = dlX;
end

end

function [XTransformed,YTransformed,numTimeSteps] = preprocessMiniBatch(XCell,YCell) 

    numTimeSteps = cellfun(@(sequence) size(sequence,2),XCell);
    sequenceLength = max(cellfun(@(sequence) size(sequence,2),XCell));
    
    miniBatchSize = numel(XCell);
    numFeatures = size(XCell{1},1);    
    classes = categories(YCell{1});
    numClasses = numel(classes);
    
    szX = [numFeatures miniBatchSize sequenceLength];
    XTransformed = zeros(szX,'single');
    
    szY = [numClasses miniBatchSize sequenceLength];
    YTransformed = zeros(szY,'single');
    
    for i = 1:miniBatchSize
        predictors = XCell{i};
        
        responses = onehotencode(YCell{i},1);
        
        % Left pad.
        XTransformed(:,i,:) = leftPad(predictors,sequenceLength);
        YTransformed(:,i,:) = leftPad(responses,sequenceLength);
        
    end

end

function sequencePadded = leftPad(sequence,sequenceLength)

[numFeatures,numTimeSteps] = size(sequence);

paddingSize = sequenceLength - numTimeSteps;
padding = zeros(numFeatures,paddingSize);

sequencePadded = [padding sequence];

end