function Model=ipls(X,Y,no_of_lv,prepro_method,intervals,xaxislabels,val_method,segments)
%   % Function to calculates the interval models based on PLS
%   Function:
%   Model=ipls(X,Y,no_of_lv,prepro_method,intervals,xaxislabels,val_method,segments)
%   --------------------------------INPUT-------------------------------------------------
%   X               Matrix (n,p), predictor matrix (assumed to be center)
%   Y               Matrix (n,m), predictand (NOTE: Y is allways autoscaled)
%   no_of_lv        the maximum number of PCA or PLS components
%   prepro_method   'mean', 'auto', 'mscmean' or 'mscauto' (msc is performed in each interval)
%   interval        number of intervals. If intervals is a row vector divisions are made based on the elements
%   xaxislabels     (self explainable)
%   val_method      'test', 'full', 'syst111', 'syst123', 'random', or 'manual'; the last five are cross validation based methods
%
%   --------------------------------OUTPUT------------------------------------------------
%   Model           a structured array containing all model information
%
%   --------------------------------Example-----------------------------------------------
%   Model=ipls(Xcal,ycal,10,'mean',20,xaxis,'syst123',5)
%
%   --------------------------------Reference---------------------------------------------
%   This rotine was adapted from the code from Chemometrics Group 
%   KVL, Copenhagen, Denmark (Lars Nørgaard, July 2004)
%
%   This is a part of the GNAT
%   Copyright  2021  <Mathias Nilsson>%
%   This program is free software; you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation; either version 2 of the License, or
%   (at your option) any later version.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License along
%   with this program; if not, write to the Free Software Foundation, Inc.,
%   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%
%   Dr. Mathias Nilsson
%   School of Chemistry, University of Manchester,
%   Oxford Road, Manchester M13 9PL, UK
%   Telephone: +44 (0) 161 306 4465
%   Fax: +44 (0)161 275 4598
%
%   Hugo da Silva Rocha, PhD Student
%   School of Chemistry, University of Manchester,
%   hugo.rocha@postgrad.manchester.ac.uk

if nargin==0
   disp(' ')
   disp(' Model=ipls(X,Y,no_of_lv,prepro_method,intervals,xaxislabels,val_method,segments);')
   disp(' ')
   disp(' Example:')
   disp(' Model=ipls(X,Y,7,''mean'',20,xaxis,''syst123'',5);')
   disp(' ')
   return
end

%% Error checks
if ~ismember(val_method,{'test', 'full', 'syst123', 'syst111', 'random', 'manual'})
    disp(' Not allowed validation method')
    Model=[];
    return
end

if ~ismember(prepro_method,{'mean', 'auto', 'mscmean', 'mscauto', 'none'})
    disp(' Not allowed preprocessing method')
    Model=[];
    return
end

if strcmp(lower(val_method),'manual') & ~iscell(segments)
    disp('You need to specify the manual segments in a cell array, see makeManualSegments')
    Model=[];
    return
end

if strcmp(lower(val_method),'manual') & iscell(segments)
   Nsamples=0;
   for j=1:max(size(segments))
      Nsamples=Nsamples + max(size(segments{j}));
   end
   if size(X,1)~=Nsamples
      disp('The number of samples in X does not correspond to the total number of samples in segments')
      Model=[];
      return
   end
end
%% End error checks

Model.type='iPLS';
Model.rawX=X;
Model.rawY=Y;
Model.no_of_lv=no_of_lv;
Model.prepro_method=prepro_method;
Model.xaxislabels=xaxislabels; % Final use of xaxislabels in this file; i.e. if reversed axes are present this should be taken care of in iplsplot
Model.val_method=val_method;
Model.breakTag = 0;

[n,m]=size(X);
if strcmp(lower(Model.val_method),'full') | nargin <8
   Model.segments=n;
else
   Model.segments=segments;
end

[nint,mint]=size(intervals);
if mint > 1 % BinPCA limits import
%     Model.allint=[(1:round(mint/2)+1)' [intervals(1:2:mint)';1] [intervals(2:2:mint)';m]];
%     Model.intervals=round(mint/2);
%     Model.intervalsequi=0;

    % For binning limits
    Model.intervals=nint-1; % maybe minus one
    Model.allint=intervals;
    Model.intervalsequi=0;

else
    Model.intervals=intervals;
    vars_left_over=mod(m,intervals);
    N=fix(m/intervals);
    % Distributes vars_left_over in the first "vars_left_over" intervals
    startint=[(1:(N+1):(vars_left_over-1)*(N+1)+1)'; ((vars_left_over-1)*(N+1)+1+1+N:N:m)'];
    endint=[startint(2:intervals)-1; m];
    Model.allint=[(1:intervals+1)' [startint;1] [endint;m]];
    Model.intervalsequi=1;
end

% Local calibration
for i=1:size(Model.allint,1)
   if i<size(Model.allint,1)
      home, s = sprintf('Working on interval no. %g of %g...',i,size(Model.allint,1)-1); disp(s)
   else
      home, disp('Working on full spectrum model...')
   end
   [n,m] = size(X(:,[Model.allint(i,2):Model.allint(i,3)]));
   if m < Model.no_of_lv
      warndlg((sprintf('The number of X variables is lower than the selected number of components Considerer reducing the number of intervals')),'Warning'); 
      Model.breakTag = 1;
      break
   end
   Model.PLSmodel{i}=sub_pls_val(X(:,[Model.allint(i,2):Model.allint(i,3)]),Y,Model.no_of_lv,Model.prepro_method,Model.val_method,Model.segments);
end
