%% Overview
% The purpose of this code is to take text files from the local directory
% that are spectral data from spectroscopic or microspectrocopic techniques
% and convert it into a format whereby feature extraction can take place
% for ML applications. The code transforms the data into a matrix that can
% be rescaled to relative proportions, converts to absorbance from
% transmittance, reduces the range of wave numbers, plot the resulting
% data, and gathers the necessary predictors from MATLAB's in-built feature
% extraction functions and a few nove; feature extractions that looks at
% the behavior of the spectra via a "cumulative intensity function" (20th to principal
% wave number). NOTE: May need tweaking if there is a limited amount of
% maxima

% Change labels and switch cases, at will, to expedite feature extraction!
% Ex: cvar sets up the categorization of the matrices and should be labeled
% accordingly

%% Loads files, labels, and converts to a matrix

swc = "on"; %Turn switch on or off for table write

ds = tabularTextDatastore('Unknown (.txt)\Unknown Spectra Master CSV.csv');
k = 1;
data_l = read(ds);
data_l = table2array(data_l);
%% Switch case for data type (NOTE: Arrays must be matching in length for ALL files)
v = 1; % Comment/uncomment for debugging/code building purposed. (SET TO DESIRED MODULE TO BYPASS INPUT
% v = input('Is your data from OS or elsewhere? (Type "1" for OS or "2" for elsewhere): ');
switch v
    case 1
        l_files = length(data_l(1,:)) - 1;

        for i = 1:l_files
            B(:,k:k+1) = [data_l(:,1) data_l(:,i+1)];
            k = k + 2;
        end

        reset(ds)
    case 2
        l_files = length(data_l);

        for i = 1:l_files
            B(:,k:k+1) = [data_l(:,k) data_l(:,k+1)];
            k = k + 2;
        end

        reset(ds)
    otherwise
        disp('Error: Incorrect input.')
end

%% Absolute to Relative Intensity Conversion
v = 2; % Comment/uncomment for debugging/code building purposed. (SET TO DESIRED MODULE TO BYPASS INPUT
% v = input('Conversion from absolute to relative intensity needed? (Type: "1" for yes or "2" for no):')
switch v
    case 1
        for i = 1:l_files
            B(:,2*i) = rescale(B(:,2*i));
        end
    case 2 
        disp('Moving on...')
end
%% Transmittance to Absorbance
v = 2; % Comment/uncomment for debugging/code building purposed. DELETE WHEN DONE.
% v = input('Need conversion from transmittance to absorbance (Type: "1" for "yes" or "2" for "no")? ');

switch v
    case 1
        for i = 1:l_files
            B(:,2*i) = 1 - B(:,2*i);
        end
    case 2
        disp('Continuing on...')
    otherwise
        disp('Error: Incorrect input. Continuing on...')
end


%% Reduce Dataset to input LB to UB
v = 2; % Comment/uncomment for debugging/code building purposed. (SET TO DESIRED MODULE TO BYPASS INPUT
% v = input('Do you need to reduce your wavelength range (1/cm)? (Type: 1 for "yes" or "2" for no):');

switch v
    case 1
        LB = input('What is your lower bound?:');
        UB = input('What is yout upper bound?:');

        x = 1;
        i = 1;

        while x == 1 
            if B(i,1) < LB
                B(i,:) = [];
            end
            if B(i,1) >= LB
                if B(end,1) > UB || B(end,1) == 0
                    B(end,:) = [];
                end
                if B(end,1) <= UB && B(end,1) ~= 0
                    break
                end
            end
        end

    case 2
        disp('Moving on...');
    otherwise
        disp('Input error for "Dataset Reduction"')
end

%% Plot for Data
v = 2; % Comment/uncomment for debugging/code building purposed. (SET TO DESIRED MODULE TO BYPASS INPUT
% v = input('Plot matrix data? (Type: "1" for yes or "2" for no):');
switch v
    case 1

    j = 1;
    figure(1)
    for i = 1:l_files
        plot(B(:,j),B(:,j+1))
        j = j + 2;
        hold on
    end

    case 2
        disp('Moving on...')
    otherwise
        disp('Error: Plotting module.')
end


%% Artificial Dataset (Random Interpolation)
v = 2; % Comment/uncomment for debugging/code building purposed. (SET TO DESIRED MODULE TO BYPASS INPUT
% v = input('Artificial dataset? (Type: "1" for yes, "2" for no):');

% Be sure to rename variables before files are saved in .mat format. Simply
% concatenate tables AFTER feature extraction into a master table. Cvar
% should be uniquely identifiable

l = 2;
switch v
    case 1
    filenum = input('How many synthetic spectra is needed?:');

    C = zeros(length(B(:,1)),l_files);
    D = zeros(length(B(:,1)),filenum);
    r = rand(1,l_files);
    r = r/sum(r);
    
    for n = 1:filenum
        for i = 1:l_files-1
            C(:,i) = B(:,l)*r(i);
            l = l + 2;
        end
        D(:,n) = sum(C,2); %New spectra
        r = rand(1,l_files);
        r = r/sum(r);
        l = 2;
        disp(n)
    end
    D = [B(:,1) D];
    case 2
    disp('Moving on...')
    otherwise
        disp('Error: Artificial dataset')
end

   

%% Feature Extraction
v = 3; % Comment/uncomment for debugging/code building purposed. (SET TO DESIRED MODULE TO BYPASS INPUT
% v = input('Version 1 or 2? (Type: "1" for v1, "2" for v2, or "3" for v3):')


l_generatedfiles = l_files;

abs_max = zeros(l_generatedfiles,1);
sec_max = zeros(l_generatedfiles,1);
thr_max = zeros(l_generatedfiles,1);
width = zeros(l_generatedfiles,1);
width_2 = zeros(l_generatedfiles,1);
width_3 = zeros(l_generatedfiles,1);
prominence = zeros(l_generatedfiles,1);
prominence_2 = zeros(l_generatedfiles,1);
prominence_3 = zeros(l_generatedfiles,1);
location = zeros(l_generatedfiles,1);
location_2 = zeros(l_generatedfiles,1);
location_3 = zeros(l_generatedfiles,1);
absvalint_secderiv = zeros(l_generatedfiles,1);
avg_abs_over_absolute_max = zeros(l_generatedfiles,1);
lth = length(B(:,1));

switch v
    case 1
        disp('Moving on...')
    case 2
        int = zeros(20,1);
        pmod_par_aggreg = zeros(l_generatedfiles,1);
        RSS_pmod = zeros(l_generatedfiles,1);
        corr_pmod = zeros(l_generatedfiles,1);
        
        powers = zeros(19,1);
        smod_par_aggreg = zeros(l_generatedfiles,1);
        RSS_smod = zeros(l_generatedfiles,1);
        corr_smod = zeros(l_generatedfiles,1);
    case 3
        int = zeros(20,1);
        nsigmod_par_aggreg = zeros(l_generatedfiles,1);
        RSS_nsigmod = zeros(l_generatedfiles,1);
        corr_nsigmod = zeros(l_generatedfiles,1);

        powers = zeros(19,1);
        meanpw_5_15 = zeros(l_generatedfiles,1);
        tspower = zeros(l_generatedfiles,1);

        pos = zeros(l_generatedfiles,1);
    
    otherwise
        disp('Error: Setting zero arrays. Defaulted to v1')
end




cvar = repmat('Unk_v3',[l_generatedfiles, 1]); %CHANGE!!!!

m = 1;

for i = 1:l_generatedfiles %loop that extracts feat from spectra and 3 most principal wavenumbers
    [pks,locs,w,p] = findpeaks(B(:,2*i));
    abs_max(i,:) = max(pks);
    unq = unique(pks);
    sec_max(i,:) = unq(end-1);
    thr_max(i,:) = unq(end-2);
    index = find(pks==abs_max(i,:));
    index_2 = find(pks==sec_max(i,:));
    index_3 = find(pks==thr_max(i,:));
    index_loc = find(B(:,2*i)==abs_max(i,:));
    index_loc_2 = find(B(:,2*i)==sec_max(i,:));
    index_loc_3 = find(B(:,2*i)==thr_max(i,:));
    width(i,:) = w(index);
    width_2(i,:) = w(index_2);
    width_3(i,:) = w(index_3);
    prominence(i,:) = p(index);
    prominence_2(i,:) = p(index_2);
    prominence_3(i,:) = p(index_3);
    location(i,:) = B(index_loc,m);
    location_2(i,:) = B(index_loc_2,m); %May have to specify index due to multiple locations possessing the same intensity
    location_3(i,:) = B(index_loc_3,m);

    switch v
        case 1
        case 2
            % Power and sine reg
            % power reg
            for j = 0:19
                int(j+1,:) = unq(end-j)/abs_max(i,:);
            end
            int = flip(int); %intensities of 20th to 1st principal wave number
            principality = 1:20; %least to greatest principal wave number: 20th to 1st
        
            pft = fittype('a*principality^b','independent','principality','dependent','int');
            pmod = fit(principality',int,pft);
        
            CI_pmod = confint(pmod,.95);
            CI_A = abs(CI_pmod(2,1) - CI_pmod(1,1));
            CI_B = abs(CI_pmod(2,2) - CI_pmod(1,2));
        
            pmod_par_aggreg(i,:) = abs(pmod.a/(CI_A)) + abs(pmod.b/(CI_B)); %Aggregate parameter for first regression
        
        
            y_hat_p = (pmod.a.*principality.^pmod.b)';
            RSS_pmod(i,:) = sum((int-y_hat_p).^2); %Checks of model fits well.
            corr_pmod(i,:) = corr(int,y_hat_p); %
            
            % exp-sine reg of serial exponentiation (powers from 20th to 1st int by
            % nat log)
           
            for j = 1:18
                powers(j,:) = log(int(j+1))/log(int(j));
            end
        
            position = 1:19; %least to greatest intensity
        
            sft = fittype('a*exp(-b*position)*(z*sin(c*position-d))+e','independent','position','dependent','powers');
            smod = fit(position',powers,sft);
            CI_smod = confint(smod,.95);
            
            CI_a = abs(CI_smod(2,1) - CI_smod(1,1)); %Range for the CIs for every parameter (Updated for correct order)
            CI_b = abs(CI_smod(2,2) - CI_smod(1,2));
            CI_c = abs(CI_smod(2,3) - CI_smod(1,3));
            CI_d = abs(CI_smod(2,4) - CI_smod(1,4));
            CI_e = abs(CI_smod(2,5) - CI_smod(1,5));
            CI_z = abs(CI_smod(2,6) - CI_smod(1,6));
        
            smod_par_aggreg(i,:) = abs(smod.a/CI_a) + abs(smod.b/CI_b) + abs(smod.z/CI_z) + abs(smod.c/CI_c) + abs(smod.d/CI_d) + abs(smod.e/CI_e);
        
            y_hat_s = (smod.a*exp(-smod.b.*position).*(smod.z.*sin(smod.c.*position-smod.d))+smod.e)';
            RSS_smod(i,:) = sum((powers-y_hat_s).^2); %Checks for error
            corr_smod(i,:) = corr(powers,y_hat_s);
            figure (2)
            subplot(2,1,1);
            plot(principality',y_hat_p,'b',principality',int,'g-o');% Checking models fitness
    
            xlabel('Principality (Reverse)')
            ylabel('Intensity')
            legend('Regression','Observed')
            title('Power Regression Model (Intensity) - Unknown')
            hold on

            subplot(2,1,2);
            plot(position',y_hat_s,'k',position',powers,'b-o');

            xlabel('Powers (Reverse)')
            ylabel('Intensity')
            legend('Regression','Observed')
            title('Sine-Exponential Regression Model (Powers) - Unknown')
            hold on
        
        case 3 %UNDER CONSTRUCTION
        
          for j = 0:19
                int(j+1,:) = unq(end-j)/abs_max(i,:);
          end  

          int = flip(int);
          principality = 1:20;

          comb = [principality' int];
          n = principality;
          for n = principality
              if comb(n,2) >= .5
                  pos(i,:) = comb(n,1);
                  break
              else 
              end
          end

          % nsft = fittype('a_1/[1+exp(-b_1*principality+c_1)] + a_2/[1+exp(-b_2*principality+c_2)] + a_3/[1+exp(-b_3*principality+c_3)]','independent','principality','dependent','int');
          % options = fitoptions(nsft);
          % options.Lower = [.05,.05,.05,.1,.1,.1,1,1,1];
          % options.Upper = [.95,.95,.95,40,40,40,20,20,20];
          % nsigmod = fit(principality',int,nsft);
          % 
          % y_hat_ns = ((nsigmod.a_1./(1+exp(-nsigmod.b_1.*principality+nsigmod.c_1)))+(nsigmod.a_2./(1+exp(-nsigmod.b_2.*principality+nsigmod.c_2)))+(nsigmod.a_3./(1+exp(-nsigmod.b_3.*principality+nsigmod.c_3))))';
          % RSS_nsigmod(i,:) = sum((int-y_hat_ns).^2);
          % corr_nsigmod(i,:) = corr(int,y_hat_ns);

          % plot(principality',y_hat_ns,'b',principality',int,'g-o') Will
          % plot BOTH parameters together
          % 
          % CI_nsigmod = confint(nsigmod,.95); % STOPPING PLACE
          % 
          % CI_a_1 = abs(CI_nsigmod(2,1) - CI_nsigmod(1,1)); %Range for the CIs for every parameter (Updated for correct order)
          % CI_a_2 = abs(CI_nsigmod(2,2) - CI_nsigmod(1,2));
          % CI_a_3 = abs(CI_nsigmod(2,3) - CI_nsigmod(1,3));
          % CI_b_1 = abs(CI_nsigmod(2,4) - CI_nsigmod(1,4));
          % CI_b_2 = abs(CI_nsigmod(2,5) - CI_nsigmod(1,5));
          % CI_b_3 = abs(CI_nsigmod(2,6) - CI_nsigmod(1,6));
          % CI_c_1 = abs(CI_nsigmod(2,7) - CI_nsigmod(1,7));
          % CI_c_2 = abs(CI_nsigmod(2,8) - CI_nsigmod(1,8));
          % CI_c_3 = abs(CI_nsigmod(2,9) - CI_nsigmod(1,9));

          % if isnan(CI_a_1)
          %     [CI_a_1, CI_a_2, CI_a_3] = deal(.9,.9,.9); %CI fits bounds specified if not stated
          %     [CI_b_1, CI_b_2, CI_b_3] = deal(39.9,39.9,39.9);
          %     [CI_c_1, CI_c_2, CI_c_3] = deal(19,19,19);
          % end
          % 
          % nsigmod_par_aggreg(i,:) = abs(nsigmod.a_1/CI_a_1) + abs(nsigmod.a_2/CI_a_2) + abs(nsigmod.a_3/CI_a_3) + abs(nsigmod.b_1/CI_b_1) + abs(nsigmod.b_2/CI_b_2) + abs(nsigmod.b_3/CI_b_3) + abs(nsigmod.c_1/CI_c_1) + abs(nsigmod.c_2/CI_c_2) + abs(nsigmod.c_3/CI_c_3);
          % disp(i) %COUNTER
          % 
          % a_1(i,:) = nsigmod.a_1;
          % b_1(i,:) = nsigmod.b_1;
          % c_1(i,:) = nsigmod.c_1;
          % a_2(i,:) = nsigmod.a_2;
          % b_2(i,:) = nsigmod.b_2;
          % c_3(i,:) = nsigmod.c_2;
          % a_3(i,:) = nsigmod.a_3;
          % b_3(i,:) = nsigmod.b_3;
          % c_3(i,:) = nsigmod.c_3;
          
          for j = 1:18
                powers(j,:) = log(int(j+1))/log(int(j));
          end
          
          meanpw_5_15(i,:) = mean(powers(5:15)); % Only looking at unique region in the middle of the powers curve

          % figure (2)
          % plot(principality',y_hat_ns,'b',principality',int,'g-o');% Checking models fitness
          % 
          % xlabel('Principality (Reverse)')
          % ylabel('Intensity')
          % legend('Regression','Observed')
          % title('Triple Sigmoidal Model (Intensity) - BLANK')
          % hold on

          otherwise
    end

    avg_abs_over_absolute_max(i,:) = mean(B(:,2*i))/abs_max(i,:);
    dAdx = diff(B(:,2*i))./diff(B(:,m));
    dAdx(lth) = 0;
    d_dAdx = diff(dAdx)./diff(B(:,m));
    d_dAdx(lth) = 0;
    absvalint_secderiv(i,:) = trapz(B(:,m),abs(d_dAdx));
 
    m = m + 2;
end

%% Writing to Table
switch v
    case 1
        Unk_proc_v2 = table(sec_max,thr_max,width,width_2,width_3, ...
        prominence,prominence_2,prominence_3,location,location_2,location_3, ...
        avg_abs_over_absolute_max,absvalint_secderiv,cvar); 
    case 2
        Unk_v2 = table(sec_max,thr_max,width,width_2,width_3, ...
        prominence,prominence_2,prominence_3,location,location_2,location_3, ...
        avg_abs_over_absolute_max,absvalint_secderiv,pmod_par_aggreg,smod_par_aggreg,cvar);
        disp('Median of Correlations and RSS for Power Regression - Unknown')
        median(corr_pmod)
        median(RSS_pmod)
        disp('Median of Correlations and RSS for Sin-Exp Regression - Unknown')
        median(corr_smod)
        median(RSS_smod)
    case 3
        Unk_v3 = table(sec_max,thr_max,width,width_2,width_3, ...
        prominence,prominence_2,prominence_3,location,location_2,location_3, ...
        avg_abs_over_absolute_max,absvalint_secderiv,pos,meanpw_5_15,cvar);
    otherwise
        disp('Input error: table writing.')
end

%Relative int nullifies the importance of "abs_max" since all abs_max
%for all classes are 1.