function anovarep(varargin)
% ANOVAREP - Analysis of variance for repeated measures. 
% This function executes the analysis of variance when subjects underwent
% several treatments. This function is similar to ANOVA2 Matlab Function,
% but there are three differences:
% 1) the output of ANOVA table;
% 2) the graphical plot of anova table;
% 3) if p-value<alpha this function executes the Holm-Sidak test for multiple
% comparison test to highlight differences between treatments.
% 
% Syntax: 	ANOVAREP(X,ALPHA)
%      
%     Inputs:
%           X - data matrix. 
%           ALPHA - significance level (default = 0.05).
%     Outputs:
%           - Anova table.
%           - Graphical plot of anova table.
%           - Holm-Sidak test (eventually)
%
%      Example: demoanovarep
%
%           Created by Giuseppe Cardillo
%           CEINGE - Advanced Biotechnologies
%           Via Comunale Margherita, 482
%           80145
%           Napoli - Italy
%           cardillo@ceinge.unina.it

%Input error handling
args=cell(varargin);
nu=numel(args);
if isempty(args)
    error('stats:anovarep:TooFewInputs','At least one input is required.');
elseif nu>2 
    error('stats:anovarep:TooMuchInputs','Max two inputs are required.');
else
    default.values = {[],0.05}; %default value of alpha
    default.values(1:nu) = args;
    [x alpha] = deal(default.values{:});
    if isvector(x)
        error('Warning: x must be a matrix, not a vector.');
    end
    if (any(isnan(x(:)))) %check the matrix
        error('stats:anovarep:DataNotBalanced',...
            'NaN values in input not allowed.  Use anovan instead.');
    end
    if ~all(isnumeric(x(:))) || any(isinf(x(:))) || isempty(x)
        error('The x values must be numeric and finite')
    end
    if nu==2 %if alpha was given
        if ~isscalar(alpha) || ~isnumeric(alpha) || ~isfinite(alpha) || isempty(alpha)
            error('Warning: ALPHA value must be a numeric and finite scalar');
        end
        if alpha <= 0 || alpha >= 1 %check if alpha is between 0 and 1
            error('Warning: ALPHA must be comprised between 0 and 1.')
        end        
    end
end
clear args default nu

[n,m]=size(x); %n=subjects; m=treatments;
T=mean(x); %Mean of treatment
S=mean(x,2); %Mean of subject
Xbar=sum(x(:))/(m*n); %General mean

SStra=m*sum((S-Xbar).^2); %Variability among subjects
GLtra=n-1; %degrees of freedom
MStra=SStra/GLtra; % variance of population estimed from subjects

SSentro=sum(sum((x-repmat(S,1,m)).^2,2)); %Variability within subjects
GLentro=n*(m-1); %degrees of freedom

SStot=SStra+SSentro; %Total Variability
GLtot=GLtra+GLentro; %Degrees of freedom

%The variability within subjects can be decomposed in:

SSt=n*sum((T-Xbar).^2); %Variability among treatments
GLt=m-1; %degrees of freedom
MSt=SSt/GLt; % variance of population estimed from treatments

SSr=SSentro-SSt; %Residual variability
GLr=(n-1)*(m-1); %degrees of freedom
MSr=SSr/GLr; % variance of population estimed from residuals

F=[MStra MSt]./MSr;
panova=1-fcdf(F,[GLtra GLt],GLr); %p-value

%Formatting for ANOVA Table printout.
Table{6,6} = [];   
Table(1,1:6) = {'Variability' 'SS' 'df' 'MS' 'F' 'p-value'};
Table(2:6,1)={'Total';'Among subjects';'Within subjects';'Among treatments';'Residual'};
Table(2:6,2)={SStot; SStra; SSentro; SSt; SSr};
Table(2:6,3)={GLtot; GLtra; GLentro; GLt; GLr};
Table([3 5 6],4)={MStra; MSt; MSr};
Table([3 6],5)={F(1); F(2)};
Table([3 6],6)={panova(1); panova(2)};

if panova(2)<alpha
    footer='Almost one of the treatments is the cause of variation';
else
    footer='Variation is due to chance';
end
H=figure('Position',[18 694 560 147]);
statdisptable(Table, 'ANOVA FOR REPEATED MEASURES', 'ANOVA Table', footer,[-1 -1 0 -1 2 4],H);

%Display bar a bar graph of anova table
H=figure;
set(H,'Position',[598 406 560 406]);
y=[0 0 1 1];
hold on
h1=fill([0 SStot SStot 0],y,'c');
y=y+1;
h2=fill([0 SStra SStra 0],y,'y');
h3=fill([0 SSentro SSentro 0]+SStra,y,'r');
y=y+1;
h4=fill([0 SSt SSt 0]+SStra,y,'g');
h5=fill([0 SSr SSr 0]+SStra+SSt,y,'b');
hold off
legend([h1 h2 h3 h4 h5],'Total','Among subjects','Within subjects','Among treatments','Residual','Location','NorthWest')
title('Sources of Variability')
clear S Xbar SStra GLtra SSentro GLentro SStot GLtot SSt GLt MSt SSr F
clear y h1 h2 h3 h4 h5 Table

%If Panova<alpha execute the Holm-Sidak test to close off the differences
%in anova
if panova(2)<alpha
    a=m-1; %rows of probability matrix
    c=m*(m-1)/2; %max number of comparisons
    count=0; %counter
    p=ones(1,c); %preallocation of p-value vector
    pb{c,2} = []; %preallocation of p-value matrix
    denom=realsqrt(2*MSr/n); %the denominator is the same for each comparison
    for i=1:a
        for j=i+1:m
            count=count+1;
            t=abs(diff(T([i j])))/denom; %t-value
            p(count)=(1-tcdf(t,GLr))*2; %2-tailed p-value vector
            pb(count,:)={strcat(int2str(i),'-',int2str(j));num2str(p(count))}; %Matrix of the p-values
        end
    end
    clear a m t count i j %clear unnecessary variables
    [p,I]=sort(p); %sorted p-values
    pb=pb(I,:);
    j=1:c; %How many corrected alpha value?
    alphacorr=1-((1-alpha).^(1./(c-j+1))); %Sidak alpha corrected values
    clear j %clear unnecessary vector
    %Compare the p-values with alpha corrected values. 
    %If p<a reject Ho; else don't reject Ho: no more comparisons are required.
    Table{c+1,4} = [];   %Formatting for Holm-Sidak Table printout.
    Table(1,1:4) = {'Test' 'p-value' 'alpha' 'Comment'};
    comp=1; %compare checker
    row=2;
    Table(2:end,1:2)=pb;
    for h=1:c
        if comp %Comparison is required
            Table(row,3)={num2str(alphacorr(h))};
            if p(h)<alphacorr(h)
                Table(row,4)={'Reject H0'};
            else
                Table(row,4)={'Fail to reject H0'};
                comp=0; %no more comparison are required
            end
        else %comparison is unnecessary
            Table(row,3:4)={'No comparison made';'H0 is accepted'};
        end
        row=row+1;
    end
    H=figure('Position',[18 186 560 420]);
    statdisptable(Table,'','Holm-Sidak multiple t-test','',[-1 -1 0 -1 2 4],H);
end