function [out] = SingClassLMOCVfusIn(Xin, wave, tuneMax, nCV, nCal, nOutPure, nInNonPure, Outlier, seed,varargin)
% % function [out] = SingClassLMOCVfusIn(Xin, wave, tuneMax, nCV, nCal, nOutPure, nInNonPure, Outlier, seed,varargin)

% FUNCTION 1
% This is the first function (1 out of 3) which calculates the outlier
% measures for one-class classification for one or multiple instruments/preprocessing methods
% with a window of increasing tuning parameters (tuneMax)

%|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
%| NOTE: Use SingClassFusion.m next                                               | 
%|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|

%{
Inputs:
    Xin        - a cell array (n instruments [nInst] by nClasses [nC]) of 
                 spectral data where each cell is n samples by p wavelenghs
                 (cell is 1 x nC); NOTE: nC is two, where the first column 
                 is the class of interest and the second column is other
                 samples that are tested against the class of interest
    wave       - 1 by nInst cell of the actual wavelengths used for each
                 Instrument.
                 If no wavelength, enter 0 (No EISC merits...)
    tuneMax    - The maximum tuning parameter for the eigenvector based
                 outlier measures
    nCV        - The number of cross validation splits desired
    nCal       - The number of samples that define the target class
    nOutPure   - The number of validation samples from the target class
    nInNonPure - The number of validation samples from the non-target
                 class (column 2 of Xin)  
    Outlier    - inputing true: Run with Outlier detection on the target class.
                 inputing false: NOT run with outlier detection on the target class.
    seed       - Random number generator index; The same seed values produces
                 the same random numbers
    
Functions used:
    ctdisp.m
        This is a counter function that shows you what split you are on.
    meth1cleanX.m
        Outlier detection used to clean a calibration set as desribed in
                    % Brownfield, B., & Kalivas, J. H. (2017). Consensus outlier
                    %  detection using sum of ranking differences of common and
                    %  new outlier measures without tuning parameter selections.
                    %  Analytical chemistry, 89(9), 5087-5094.
        where only the spectral outlier mesures are used.
    outmeth1X.m
        Calculates the outlier measures used for one-class classification

Outputs:
    input     - The inputs that are used to run one-class classification
                    Xin - See above
                    wave - See above
                    tuneMax - See above
                    nCV - See above
                    nCal - See above
                    nOutPure - See above
                    nInNonPure - See above
                    PureSampVal - A matrix (nCalValidation by nCV) that
                                 contains the index of the target validation
                                 samples for each cross validation split
                    NonPureSampIn - A matrix (nValidation by nCV) that
                                    contains the index of the non-target
                                    validation samples for each cross
                                    validation split
                    rpP - A matrix (nTargetClassSamples by nCV) that
                          contains the reshuffled index for each sample in
                          the target class for each cross validation split
                    rpNP - A matrix (nNonTargetClassSamples by nCV) that
                           contains the reshuffled index for each sample in
                           the non-target class for each cross validation
                           split
                    seed - See above
                                    
    fusInSing - A cell array (nInstruments by nClasses(2) by nCV) that
                contains all of the outlier measures for each split used
                for one-class classification. The struct file has fields
                corresponding to the  This is what is the input
                for SingClassFusion.m
                 Contains (Number of fields correspond to each validation
                           sample)
                   - input: The input used to calcuated the outlier
                             measures
                             X - The target class samples with the the
                                 validaion sample as the very last row
                             wave - The wavelengths for the spectra
                             tune - The maximum tuning parameter window
                             tuneR - The maximum tuning paramter window as
                                     a vector
                             xval - NOT USED
                             sig - The standard deviations for outlier
                                   detection
                  - srdin: The calculated outlier measures for each sample
                           that are normalized to unit length
                  - srdinunc: The calculated oulier measures for each
                              samples (Raw values)
                  - fusMerit: The names of the outlier measure which
                              correspond to each cell array in srdin
                              and srdinunc
    XOutDet  -  (This output only there when Outlier = true) A 1 by
                nCV cell array that contains the clean target samples
                for each of the cross validation splits.

/// Created by Brett Brownfield & Tony Lemos August 1, 2018 (Last edited on 7/10/19)
/// Department of Chemistry, Idaho State University, Pocatello, Idaho 83209 USA
%}

% Checking the inputs
assert(nargin<=9,'You have %d too many inputs for this function! (Max number of inputs: 9)',nargin-9)

if nargin<9, seed = 0; end
if nargin<8, Outlier = false; end
if nargin<7, nInNonPure=1; % Default to only testing 1 sample
    assert(size(Xin{1,1},1)==1, 'Need to have more than 1 sample to define a class')
end

if nargin<6, nOutPure=1; % Default to only testing 1 sample
    assert(size(Xin{2,1},1)==1, 'Need to have more than 1 sample to define a class')
end
if nargin<5
   nCal = size(Xin{1,1},1)-1; 
end
if nargin<4, nCV=10;end
if nargin<3, tuneMax=nan; end
if nargin<2,wave=0; end

% Asserting that the samples can be split up into cal and val in class of interest
assert((nCal+nOutPure<=size(Xin{1,1},1)),'Cannot have the sum of nCal and nOutPure be greater than %d',size(Xin{1,1},1))


warning('off');

% Default; Using all of the oulier measures for one-class classification
merit = {'md', 'sint', 'qres', 'dc', 'vm'};

[nInst,nC]=size(Xin);
assert(nC>=2,'Need to have at least two classes for one-class classification')

nsamp = nan(1,nC); % Each instrument should have the same number of samples for each class

for i=1:nC, nsamp(i)=size(Xin{1,i},1);end

%Determining tuneMax if nothing was inputed
if isnan(tuneMax), tuneMax=min(nsamp(1))-2; end

%Making wave a cell if a vector
if ~iscell(wave), wave={wave};end
nVal = nan(1,nC-1);
nCal2=nsamp(1)-nOutPure; %Determining the validation samples from cal. split 


for ii=2:nC
    nVal(ii-1)=nsamp(ii)-nInNonPure; % Choosing the last seeded values to be the test samples
end


% Setting the seed
rng(seed);

% If no samples were specifically desired for the non-pure samples

rpNP=cell(1,nC-1);
for ii  = 2:nC
    rpNP{1,ii-1} = nan(nsamp(ii),nCV);
    for i=1:nCV
        rpNP{1, ii-1}(:,i) = randperm(nsamp(ii));
    end
end


% %Making wave a rpNP if a vector
if ~iscell(rpNP), rpNP={rpNP};end 

% If no samples were specifically desired for the pure samples
    rpP=nan(nsamp(1), nCV);
    for i=1:nCV
        rpP(:, i)=randperm(nsamp(1));
    end

% Makes tuneMax, tunePLS, and nnMax into array thats nInst x 1, in case user
% only used 1 set of tuning parameter
if size(tuneMax,1)==1, tuneMax=repmat(tuneMax, nInst, 1); end


%Saving Inputs
out.input.Xin=Xin;
out.input.wave=wave;
out.input.tuneMax=tuneMax;
out.input.nCV=nCV;
out.input.nCal=nCal;
out.input.nOutPure=nOutPure;
out.input.nInNonPure=nInNonPure;
out.input.PureSampVal=rpP(nCal2+1:end,:);
NonPureSampVal = cell(1,nC-1);
for j=1:nC-1, NonPureSampVal{1,j} = rpNP{1,j}(nVal(j)+1:end,:);end
out.input.NonPureSampIn=NonPureSampVal;
out.input.rpP=rpP;
out.input.rpNP=rpNP;
out.input.seed=seed;
out.input.merit=merit;

sig = 3; % Don't know if this actually is needed

%preallocation
fusInSing=cell(nInst,nC,nCV);
XOutDet = cell(nInst,nCV);
if Outlier
outCleanXcal = cell(nInst,nCV);
end

% Calculating inputs
for i=1:nCV
    
    for j=1:nInst
        disp(['Split #', num2str(i), '  Instrument #', num2str(j)])
        XbaseCal=Xin{j,1}(rpP(1:nCal, i),:);
        XbaseVal=Xin{j,1}(rpP(nCal2+1:end, i),:); % Target validation
        
        
        % If doing outlier detection
        if Outlier
            % Preallocating for outlier detection
            sigOutlier = 3; % 3 sigma is the standard value used for outlier cleaning

            % This cleans the target class using outiler detection
            outCleanXcal{j,i}=meth1cleanX(XbaseCal, wave{j}, [1 tuneMax(j)], sigOutlier, false);
            XbaseCalClean=outCleanXcal{j,i}.srdX(end).input.X;
            XOutDet{j,i} = XbaseCalClean;
           for k=1:nC
                if k==1
                    
                    for kk=1:nOutPure
                        ctdisp(kk)
                        % Calculating outlier measures
                        fusInSing{j, k, i}(kk)=outmeth1X([XbaseCalClean;XbaseVal(kk,:)], wave{j}, tuneMax(j), ...
                            [1 tuneMax(j)], [], false, sig, false, false,merit); % WITH OUTLIER DETECTION
                    end
                else
                    XbaseVal2=Xin{j,k}(rpNP{1,k-1}(nVal(k-1)+1:end,i),:); % Non-target validation
                    for kk=1:nInNonPure
                        ctdisp(kk)
                        % Calculating outlier measures
                        fusInSing{j, k, i}(kk)=outmeth1X([XbaseCalClean;XbaseVal2(kk,:)], wave{j}, tuneMax(j),...
                            [1 tuneMax(j)], [], false, sig, false, false,merit); % WITH OUTLIER DETECTION
                    end
                end
            end
            out.XOutDet = XOutDet; % The X used for the target class
        else
            
            for k=1:nC
                if k==1
                    for kk=1:nOutPure
                        ctdisp(kk)
                        % Calculating outlier measures
                        fusInSing{j, k, i}(kk)=outmeth1X([XbaseCal;XbaseVal(kk,:)], wave{j}, tuneMax(j),...
                            [1 tuneMax(j)], [], false, sig, false, false, merit); % WITHOUT OUTLIER DETECTION
                    end
                else
                    XbaseVal2=Xin{j,k}(rpNP{1,k-1}(nVal(k-1)+1:end,i),:); % Non-target validation
                    for kk=1:nInNonPure
                        ctdisp(kk)
                        % Calculating outlier measures
                        fusInSing{j, k, i}(kk)=outmeth1X([XbaseCal;XbaseVal2(kk,:)], wave{j}, tuneMax(j),...
                            [1 tuneMax(j)], [], false, sig, false, false,merit); % WITHOUT OULIER DETECTION
                    end
                end
            end
        end
    end
end
warning('on');
%% Saving outputs
out.fusInSing=fusInSing;

