function [outputModel, MSFValue, validityFunctionValue] = calculateModelOutput(obj,input,output)
% CALCULATEMODELOUTPUT calculates the output model of the given input and
% output sequence. If no inputs and outputs are given "calculateModelOutput"
% uses the Regressors stored in the gobal model object. The information
% about the outputs is only needed to handle dynamic systems.
%
% [outputModel, MSFValue, validityFunctionValue] = calculateModelOutput(obj,input,output)
%
%
% OUTPUTS:
%
% outputModel:          (N x q)     Matrix of model outputs
%
% MSFValue:             (N x M)     Matrix of (non-normalized) membership
%                                   function values
%
% validityFunctionValue (N x M)     Matrix of normalized validity function
%                                   values
%
%
% INPUTS:
%
% obj:                  (object)    local model object containing all
%                                   relevant net
%
% input:                (N x p)     (optional) Data matrix containing
%                                   physical inputs
%
% output:               (N x q)     (optional) Data matrix containing
%                                   physical outputs. These are only needed
%                                   for dynamic systems.
%
%
% SYMBOLS AND ABBREVIATIONS:
%
% LM:  Local model
%
% p:   Number of inputs (physical inputs)
% q:   Number of outputs
% N:   Number of data samples
% M:   Number of LMs
% nx:  Number of regressors (x)
% nz:  Number of regressors (z)
%
%
% LMNtool - Local Model Network Toolbox
% Tobias Ebert, 16-November-2011
% Institute of Mechanics & Automatic Control, University of Siegen, Germany
% Copyright (c) 2012 by Prof. Dr.-Ing. Oliver Nelles

% 18.11.11  help updated


if ~exist('input','var') && ~exist('output','var')
    % if no input and output is given use the precalculated ones. This
    % if-else combinations saves a lot of computation time in training!
    xRegressor = obj.xRegressor;
    zRegressor = obj.zRegressor;
else
    if ~isempty(obj.scaleInput)
        % if input should be scaled
        input = obj.scaleInput.scale(input);
    end
    
    if ~isempty(obj.scaleOutput) && exist('output','var')
        % if output should be scaled
        output = obj.scaleOutput.scale(output);
    elseif ~exist('output','var')
        % if input is given, but no output
        output = [];
    end
    
    xRegressor = obj.data2xRegressor(input,output);
    zRegressor = obj.data2zRegressor(input,output);
end

if obj.kStepPrediction <= 1 % Static net or dynamic net with one-step-ahead prediction
    
    if ~exist('input','var') && ~exist('output','var') && isprop(obj,'MSFValue')
        MSFValue = obj.MSFValue(obj.leafModels);
        validityFunctionValue = obj.calculateVFV(MSFValue);
    else
        % calculate the MSF Value of all active models
        
        if strcmp(version('-release'),'2010a')
            % workaround for R2010a
            idx = find(obj.leafModels);
            for k = 1:sum(obj.leafModels)
                MSFValue(:,k) = obj.localModels(idx(k)).calculateMSF(zRegressor);
            end
            validityFunctionValue = obj.calculateVFV(MSFValue);
        else
            %  for R2010b and later
            MSFValue = arrayfun(@(loc) loc.calculateMSF(zRegressor),obj.localModels(obj.leafModels),'UniformOutput',false);
            validityFunctionValue = obj.calculateVFV(MSFValue);
        end
        
    end
    
    %     if ~isempty(strfind(version,'R2010a'))
    %         localParameter = {obj.localModels(obj.leafModels).parameter};
    %     else
    %         localParameter = arrayfun(@(cobj) cobj.parameter,obj.localModels(obj.leafModels),'UniformOutput',false);
    %     end
    
    localParameter = {obj.localModels(obj.leafModels).parameter};
    
    outputModel = obj.calcYhat(xRegressor,validityFunctionValue,localParameter);
    
else % Dynamic net parallel simulation
    
    [outputModel,MSFValue,validityFunctionValue] = obj.simulateParallel(xRegressor,zRegressor);
    
end

%if  (exist('input','var') || ~exist('output','var')) && ~isempty(obj.scaleOutput)
%    if input or output was given (should happen only outside training)
if  ~isempty(obj.scaleOutput)
    % always unscale output
    outputModel = obj.scaleOutput.unscale(outputModel);
end

end


