function [data, obj] = scale(obj, data)
% SCALE scales the given data according to the information in the class
%
%   [scaledData, obj] = scale(obj, data)
%
% INPUTS:
%
% data  (N x dim)   unscaled data
%
% OUTPUTS:
%
% data  (N x dim)           scaled data
% obj   (dataScale class)   optional output including the scaling parameters
%
% 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, 24-April-2012
% Institute of Mechanics & Automatic Control, University of Siegen, Germany
% Copyright (c) 2012 by Prof. Dr.-Ing. Oliver Nelles

switch obj.method
    case 'unitVarianceScaling'
        % scale data to mean zero and standard deviation one
        
        if isempty(obj.parameter)
            % no previos scaling, write new parameter into obj
            [data, obj.parameter] = unitVarianceScaling_noPara(data);
        else
            % use existing scaling parameters
            data = unitVarianceScaling(data, obj.parameter);
        end
        
    case 'boxcox'
        % scale data with boxcox transformation
        
        if isempty(obj.parameter)
            %error('no parameters for boxcox transformation where given. Use boxcox_0.5 for example')
            [data, obj.parameter] = boxcox_noPara_scaling(data,obj.method);
        else
            % use existing scaling parameters
            data = boxcox_scaling(data, obj.parameter);
        end
        
        
        %case 'orthogonalScaling'
        
    otherwise
        
        if strncmpi(obj.method,'boxcox',6)
            % check if the first 6 characters for box cox transformation
            
            % scale data
            [data, obj.parameter] = boxcox_noPara_scaling(data,obj.method);
            % overwrite obj.method for faster calculation after parameters
            % have been set
            obj.method = 'boxcox';
            
        else
            error('The method you specified is not allowed')
        end
        
end


end

%% BOx Cox transformation
function [data, parameter] = boxcox_noPara_scaling(data,method)


% get the offset variable (lambda 2)
if any(data <= 0)
    parameter.offset = -min(data)+eps;
    % do add a negative offset, high minimal values should remain
    % (only necessary for multiple coloums of data)
    parameter.offset(parameter.offset<0) = 0;
else
    % set offset to zero
    parameter.offset = zeros(1,size(data,2));
end


% get lambda value for boxcox transformation
if length(method) == 6
    [data, parameter.lambda] = boxcox(data);
else
    % read lambda value
    parameter.lambda = str2double(method( regexp(method,'[.0123456789]','once'):end));
    % apply scaling
    data = boxcox_scaling(data, parameter);
end

end

function data = boxcox_scaling(data, parameter)

% scale data
% if parameter.lambda == 0
%     data = log(bsxfun(@plus,data,parameter.offset)+eps);
% else
%     data = (bsxfun(@plus,data,parameter.offset).^parameter.lambda - 1) / parameter.lambda;
% end

% scale data with matlab boxcox function
data = data + parameter.offset;
data = boxcox(data,parameter.lambda);

end


%% unitVarianceScaling
function [data, parameter] = unitVarianceScaling_noPara(data)
% scale data to mean zero and standard deviation one

% calculate mean
parameter.mean = mean(data,1);
% subtract mean
data = bsxfun(@minus,data,parameter.mean);
% calculate standard deviation
parameter.std = std(data);
% check for std = 0
if any(parameter.std == 0)
    % set std=0 to std=1
    parameter.std(parameter.std == 0) = 1;
end
% divide by standard deviation
data = bsxfun(@rdivide,data,parameter.std);
end

function data = unitVarianceScaling(data, parameter)

% give a warning if data has already been scaled
if all(mean(data) < 1e-15 & std(data) == 1)
    warning('scaleData:scaling','It seems the data is already scaled! Check your data!')
end

% scale data to mean zero and standard deviation one
data = bsxfun(@rdivide,bsxfun(@minus,data,parameter.mean),parameter.std);
end




