function out = validate_v3_Cl36(text_block,consts,verboseFlag)

% Validates a block of text input for Cl-36 exposure age calculations. 
% 
% Syntax: out = validate_v3_Cl36(text_block,consts)
%
% in is the input text string
% consts is consts file (optional, if not provided will load default). 
% 
% Returns a data structure that can be used for production rate and age
% calculations. 
% 
% Greg Balco -- Berkeley Geochronology Center
% October, 2018...December, 2018...February, 2019...
%
% Modified multiple-aliquot handling May 2022 to deal with new database
% setup. 
%
% Issues:
% 1. How to determine when exposure and formation age are the same, vs.
% infinite formation age?
% 2. Need to fix LOI assignment when target and WR both have LOI. Oops. 

if nargin < 3; verboseFlag = false; end

% Obtain constants. I am actually not sure if this is needed.


if nargin < 2
    load Cl36_consts;
end

if isempty(consts)
    load Cl36_consts;
end

% Version

out.version_validate = '0.1-dev';

% Initialize error flag

out.error = 0;

%% Step 1. Break up and sort lines. 

% Classify each line, split it up, and store it in arrays of arrays. 
% There are five possible line classifications: sample, Cl-36, major
% element, trace element, and formation age. 

% Deblank and detab. Not actually sure this is necessary. 
remains = deblank(text_block);
remains = strrep(remains,char(9),' ');
k = 1;

% These actually store data
s_lines = {};
cl36_lines = {};
me_lines = {};
te_lines = {};
t_lines = {};
% These are for bookkeeping
s_lines_nums = [];
cl36_lines_nums = [];
me_lines_nums = [];
te_lines_nums = [];
t_lines_nums = [];

% The below is all needed for sample/aliquot matching. 
init_sample_names = {};
init_cl36_aliquots = {};
init_cl36_samples = {};
init_t_aliquots = {};
init_t_samples = {};
init_me_aliquots = {};
init_me_samples = {};
init_te_aliquots = {};
init_te_samples = {};

while 1
    [current_line, remains] = strtok(remains,';');
    if isempty(current_line); break; end
    % Split up line
    current_split_line = strsplit(strtrim(current_line));
    % Data type checking for sample names. No matter what the line type, first
    % element must be a sample name.
    % Test for length
    if length(current_split_line{1}) > 32
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Sample name more than 32 characters - line ' int2str(a)];
        return;
    end
    % Test for illegal characters in sample name
    % this allows letters, numbers, underscores, and dashes only. 
    if ~isempty(regexp(current_split_line{1},'[^\w-]','once'))
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Illegal characters in sample name - line ' int2str(a)];
        return;
    end  
    % Classify line by type. 
    if (strcmp(current_split_line{2},'Cl-36') || strcmp(current_split_line{3},'Cl-36'))
        % Check for aliquot ID
        if ~strcmp(current_split_line{2},'Cl-36')
            if ~isempty(regexp(current_split_line{2},'[^\w-]','once'))
                out.error = 1;
                out.message = ['validate_v3_Cl36.m: Illegal characters in aliquot name - line ' int2str(a)];
                return;
            end 
            % store info about aliquots
            init_cl36_samples{end+1} = current_split_line{1};
            init_cl36_aliquots{end+1} = current_split_line{2};
        else
            % do nothing
        end  
        cl36_lines{end+1} = current_split_line;
        cl36_lines_nums(end+1) = k;
    elseif (strcmp(current_split_line{2},'major_elements') || strcmp(current_split_line{3},'major_elements'))
        % Check for aliquot ID
        if ~strcmp(current_split_line{2},'major_elements')
            if ~isempty(regexp(current_split_line{2},'[^\w-]','once'))
                out.error = 1;
                out.message = ['validate_v3_Cl36.m: Illegal characters in aliquot name - line ' int2str(a)];
                return;
            end 
            % store info about aliquots
            init_me_samples{end+1} = current_split_line{1};
            init_me_aliquots{end+1} = current_split_line{2};
        else
            % do nothing
        end  
        me_lines{end+1} = current_split_line;
        me_lines_nums(end+1) = k;
    elseif (strcmp(current_split_line{2},'trace_elements') || strcmp(current_split_line{3},'trace_elements'))
        if ~strcmp(current_split_line{2},'trace_elements')
            if ~isempty(regexp(current_split_line{2},'[^\w-]','once'))
                out.error = 1;
                out.message = ['validate_v3_Cl36.m: Illegal characters in aliquot name - line ' int2str(a)];
                return;
            end 
            % store info about aliquots
            init_te_samples{end+1} = current_split_line{1};
            init_te_aliquots{end+1} = current_split_line{2};
        else
            % do nothing
        end  
        te_lines{end+1} = current_split_line;
        te_lines_nums(end+1) = k;
    elseif (strcmp(current_split_line{2},'formation_age_Ma') || strcmp(current_split_line{3},'formation_age_Ma'))
        if ~strcmp(current_split_line{2},'formation_age_Ma')
            if ~isempty(regexp(current_split_line{2},'[^\w-]','once'))
                out.error = 1;
                out.message = ['validate_v3_Cl36.m: Illegal characters in aliquot name - line ' int2str(a)];
                return;
            end 
            % store info about aliquots
            init_t_samples{end+1} = current_split_line{1};
            init_t_aliquots{end+1} = current_split_line{2};
        else
            % do nothing
        end  
        t_lines{end+1} = current_split_line;
        t_lines_nums(end+1) = k;
    else
        % Anything not identified must be a sample line
        s_lines{end+1} = current_split_line;
        init_sample_names{end+1} = current_split_line{1};    
        s_lines_nums(end+1) = k;
    end
    k = k + 1;
end


%% 

% Identify unique samples and check how many aliquots they have. When there
% are multiple aliquots for a given sample, adjust everything so as to
% present that to the calculator as multiple samples. 
% Note: if there are no aliquot identifiers in the lines, this should do
% nothing. 

for a = 1:length(init_sample_names)
       aliquots_this_sample = init_cl36_aliquots(find(strcmp(init_cl36_samples,init_sample_names{a})));
       if length(aliquots_this_sample) > 0
           % At least one aliquot has been entered for this sample. Must do the following.
           % Go through all Cl36/me/te/t lines for this sample and change
           % sample name to be sample_name-aliquot_name.
           % For Cl-36
           affected_cl36 = find(strcmp(init_cl36_samples,init_sample_names{a}));
           for b = 1:length(affected_cl36)
               old_line = cl36_lines{affected_cl36(b)};
               new_line{1} = [old_line{1} '-' old_line{2}];
               new_line(2:(length(old_line)-1)) = old_line(3:end);
               % Replace line
               cl36_lines{affected_cl36(b)} = new_line;
               clear new_line;
           end
           % For ME
           affected_me = find(strcmp(init_me_samples,init_sample_names{a}));
           for b = 1:length(affected_me)
               old_line = me_lines{affected_me(b)};
               if strcmp(old_line{2},'major_elements')
                   % Case some aliquots were found in the Cl-36 data, but
                   % aren't in a ME line
                   out.error = 1;
                   out.message = 'validate_v3_Cl36.m: Can''t relate Cl-36 to major element data because aliquots were entered for Cl-36 data but are missing in major element data.';
                   return;
               end
               new_line{1} = [old_line{1} '-' old_line{2}];
               new_line(2:(length(old_line)-1)) = old_line(3:end);
               % Replace line
               me_lines{affected_me(b)} = new_line;
               clear new_line;
           end
           % For TE
           affected_te = find(strcmp(init_te_samples,init_sample_names{a}));
           for b = 1:length(affected_te)
               old_line = te_lines{affected_te(b)};
               if strcmp(old_line{2},'trace_elements')
                   % Case some aliquots were found in the Cl-36 data, but
                   % aren't in a ME line
                   out.error = 1;
                   out.message = 'validate_v3_Cl36.m: Can''t relate Cl-36 to trace element data because aliquots were entered for Cl-36 data but are missing in trace element data.';
                   return;
               end
               new_line{1} = [old_line{1} '-' old_line{2}];
               new_line(2:(length(old_line)-1)) = old_line(3:end);
               % Replace line
               te_lines{affected_te(b)} = new_line;
               clear new_line;
           end
           % For T
           % Note: this isn't really right -- the formation age should
           % normally belong to the sample -- but in the database it's
           % associated with the Cl-36 measurement. Thus, we expect these
           % lines to be identified by aliquot as well. 
           affected_t = find(strcmp(init_t_samples,init_sample_names{a}));
           for b = 1:length(affected_t)
               old_line = t_lines{affected_t(b)};
               if strcmp(old_line{2},'formation_age_Ma')
                   % Case some aliquots were found in the Cl-36 data, but
                   % aren't in a ME line
                   out.error = 1;
                   out.message = 'validate_v3_Cl36.m: Can''t relate Cl-36 to formation age data because aliquots were entered for Cl-36 data but are missing in formation age data.';
                   return;
               end
               new_line{1} = [old_line{1} '-' old_line{2}];
               new_line(2:(length(old_line)-1)) = old_line(3:end);
               % Replace line
               t_lines{affected_t(b)} = new_line;
               clear new_line;
           end
           % Now we have to change the sample names. 
           % First, change the existing sample line to have the first
           % aliquot name. 
           s_lines{a}{1} = [init_sample_names{a} '-' aliquots_this_sample{1}];
           for b = 2:length(aliquots_this_sample)
               newline = s_lines{a};
               newline{1} = [init_sample_names{a} '-' aliquots_this_sample{b}];
               s_lines{end+1} = newline;
               s_lines_nums(end+1) = s_lines_nums(a);
           end
       end

    
end


% Enumerate
out.numsamples = length(s_lines);
out.numcls = length(cl36_lines);
out.nummes = length(me_lines);
out.numtes = length(te_lines);
out.numts = length(t_lines);

% A couple more error checks. 
if out.numsamples < 1
    out.error = 1;
    out.message = 'validate_v3_Cl36.m: Can''t find any sample data lines - nothing to calculate';
    return;
end
if out.numcls < 1
    out.error = 1;
    out.message = 'validate_v3_Cl36.m: Can''t find any Cl-36 data lines - nothing to calculate';
    return;
end
if out.nummes < 1
    out.error = 1;
    out.message = 'validate_v3_Cl36.m: Can''t find any major element data lines - nothing to calculate';
    return;
end
if out.numtes < 1
    out.error = 1;
    out.message = 'validate_v3_Cl36.m: Can''t find any trace element data lines - nothing to calculate';
    return;
end


%% Set up output data structure. Note this is different from the Al-Be case
% because we don't expect arbitrary pairing. Specifically, 
%   1. Each sample line can correspond with either zero or one
%   formation_age lines.
%   2. At present we assume there is one Cl-36 line per sample.  
%   3. Each sample/Cl-36 line must have exactly one major element-WR line and
%   exactly one trace element-WR line. 
%   4. Each sample/Cl-36 line can have 0 or 1 major element-target lines. 
%
%   At some point it may be necessary to deal with multiple Cl-36 measurements
%   on one sample. At this point, however, if a sample had multiple (Cl36-me-te)
%   triplets, there would be no way to figure out which went with which.
%   So, not doing that now. 
%
% 202205. The processing in the previous section should ensure that the
% multiple aliquot case has been reconciled with this requirement. Now each
% sample/aliquot pair should be represented as a separate sample. 

% Preallocate sample, Cl-36 data structures. Sample information goes in the
% former, all analytical data goes in the latter. 

% Sample data structure has vectors with length numsamples
out.s.sample_name = cell(out.numsamples,1);
out.s.aa = out.s.sample_name;
out.s.lat = zeros(out.numsamples,1);
out.s.long = out.s.lat;
out.s.elv = out.s.lat; 
out.s.pressure = out.s.lat;
out.s.thick = out.s.lat;
out.s.rho = out.s.lat;
out.s.othercorr = out.s.lat;
out.s.E = out.s.lat;
out.s.yr = out.s.lat; % year of sample collection
out.s.rock_age_Ma = ones(out.numsamples,1)./0; % default formation age is infinity
% Note can't use zero, because zero should signal that exposure and
% formation age are the same. But, um, how do we signal that? 
out.s.delrock_age_Ma = out.s.lat; % zeros

% Cl-36 data structure has vectors with length numcls, which should be the
% same as length numsamples. 
out.n.index = zeros(out.numcls,1); % Field indexing nuclide measurement to sample number
out.n.nuclide = cell(out.numcls,1); % Nuclide/target identifier
out.n.sample_name = out.n.nuclide;
out.n.N = out.n.index; % Properly standardized nuclide concentration
out.n.delN = out.n.index; % Same, uncertainty in
out.n.Cl = out.n.index; % Cl concentration
out.n.delCl = out.n.index; % Uncertainty

% Now we have to deal with the chemical composition vectors. There can be
% two, for WR and target, and they have weight fractions of the official 24 
% elements in atomic number order:
%   [H Li B C N O Na Mg Al Si P S Cl Ar K Ca Ti Cr Mn Fe Sm Gd Th U]
%   Note that this is fractions (e.g., 0.38) not percent (e.g., 38)
%   or ppm (e.g., 380000).  
% These will go in cell arrays with numcls cells. 

out.n.wpe = cell(out.numcls,1);
for a = 1:out.numcls
    out.n.wpe{a} = zeros(1,24);
end
out.n.delwpe = out.n.wpe;
out.n.wpetarget = out.n.wpe;
out.n.delwpetarget = out.n.wpe;

% LOI is stored separately. 

out.n.LOI = out.n.index;


%% Step 3. Process sample data lines. 

for a = 1:length(s_lines)
    % Get line
    thisline = s_lines{a};
    
    % Check for length
    if length(thisline) ~= 10
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Wrong number of elements in sample line ' int2str(s_lines_nums(a))];
        return;       
    end
    
    % 1. Sample name has already been validated
	
    out.s.sample_name{a} = thisline{1};
    
    % 2. Latitude
	
	% illegal character test -- 
	% all numerical inputs may contain digits, ., e,E +, -. 
	if isempty(regexp(thisline{2},'[^\d.eE+-]','once'))
		% pass
        % Convert to number
        temp = str2double(thisline{2});
        % Check that worked
        if isnan(temp)
            out.error = 1;
			out.message = ['validate_v3_Cl36.m: Un-numericalizable latitude value - line ' int2str(s_lines_nums(a))];
            return;
        end
		% test for bounds
        if (temp > 90) || (temp < -90)
            out.error = 1;
    		out.message = ['validate_v3_Cl36.m: Latitude out of bounds - line ' int2str(s_lines_nums(a))];
            return;
        end 
		% Assign
		out.s.lat(a) = temp; clear temp;
    else
		% fail
        out.error = 1;
		out.message = ['validate_v3_Cl36.m: Illegal characters in latitude - line ' int2str(s_lines_nums(a))];
        return;
	end
    
    % 3. Longitude

	if isempty(regexp(thisline{3},'[^\d.eE+-]','once'))
		% pass
        % Convert to number
        temp = str2double(thisline{3});
        % Check that worked
        if isnan(temp)
            out.error = 1;
			out.message = ['validate_v3_Cl36.m: Sample data block - un-numericalizable longitude value - line ' int2str(s_lines_nums(a))];
            return;
        end
		% test for bounds
        if (temp > 180) || (temp < -180)
            out.error = 1;
    		out.message = ['validate_v3_Cl36.m: Longitude out of bounds - line ' int2str(s_lines_nums(a))];
            return;
        end
		% Assign
		out.s.long(a) = temp; clear temp;
    else
		% fail
        out.error = 1;
		out.message = ['validate_v3_Cl36.m: Illegal characters in longitude - line ' int2str(s_lines_nums(a))];
        return;
	end
    
    % 5. Elv/pressure flag -- get this first as it affects checks for (4)
	
	% must match one of three possible options
	if (strcmp(thisline{5},'std') || strcmp(thisline{5},'ant') || strcmp(thisline{5},'pre') );
		% pass
		out.s.aa{a} = thisline{5};
	else
		% fail
        out.error = 1;
		out.message = ['validate_v3_Cl36.m: Unknown elevation/pressure flag - line ' int2str(s_lines_nums(a))];
        return;
 	end

    % 4. Elv/pressure
	
	if isempty(regexp(thisline{4},'[^\d.eE+-]','once'))
		% pass
        % Convert to number
        temp = str2double(thisline{4});
        % Check that worked
        if isnan(temp)
            out.error = 1;
			out.message = ['validate_v3_Cl36.m: Un-numericalizable elevation/pressure value - line ' int2str(s_lines_nums(a))];
            return;
        end
		% test for bounds
        if strcmp(out.s.aa{a},'std') || strcmp(out.s.aa{a},'ant')
            if (temp < -500)
                out.error = 1;
                out.message = ['validate_v3_Cl36.m: Elevation too low -- line ' int2str(s_lines_nums(a))];
                return;
            end
		elseif strcmp(out.s.aa{a},'pre')
            if (temp > 1080) || (temp < 0)
                out.error = 1;
    			out.message = ['validate_v3_Cl36.m: Pressure out of reasonable bounds -- line ' int2str(s_lines_nums(a))];
                return;
            end
        end	
		
		% OK, pack either elv or pressure field
        if strcmp(out.s.aa{a},'std') || strcmp(out.s.aa{a},'ant')
			% store the elevation value
			out.s.elv(a) = temp;
			out.s.pressure(a) = -99;
        elseif strcmp(out.s.aa{a},'pre')
			% store the pressure value
			out.s.elv(a) = -99;
			out.s.pressure(a) = temp;
        end
        clear temp;
	else
		% fail
        out.error = 1;
		out.message = ['validate_v3_Cl36.m: Illegal characters in elevation/pressure - line ' int2str(s_lines_nums(a))];
        return;
	end
    
    % 6. Thickness
	
	if isempty(regexp(thisline{6},'[^\d.eE+-]','once'))
		% Convert to number
        temp = str2double(thisline{6});
        % Check that worked
        if isnan(temp)
            out.error = 1;
			out.message = ['validate_v3_Cl36.m: Un-numericalizable thickness value - line ' int2str(s_lines_nums(a))];
            return;
        end
		% test for bounds
		if (temp < 0)
            out.error = 1;
    		out.message = ['validate_v3_Cl36.m: Thickness less than zero - line ' int2str(s_lines_nums(a))];
            return;
        end
		% Assign
		out.s.thick(a) = temp; clear temp;
	else
		% fail
        out.error = 1;
		out.message = ['validate_v3_Cl36.m: Illegal characters in thickness - line ' int2str(s_lines_nums(a))];
        return;
	end
    
    % 7. Density
	
	if isempty(regexp(thisline{7},'[^\d.eE+-]','once'))
		% pass
        % Convert to number
        temp = str2double(thisline{7});
        % Check that worked
        if isnan(temp)
            out.error = 1;
			out.message = ['validate_v3_Cl36.m: Un-numericalizable density value - line ' int2str(s_lines_nums(a))];
            return;
        end
		% test for bounds
        if (temp < 0)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Density less than zero - line ' int2str(s_lines_nums(a))];
            return;
        end
		% Assign
		out.s.rho(a) = temp; clear temp;
	else
		% fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Illegal characters in density - line ' int2str(s_lines_nums(a))];
        return;
	end
    
    % 8. Shielding
	
    if isempty(regexp(thisline{8},'[^\d.eE+-]','once'))
		% pass
        % Convert to number
        temp = str2double(thisline{8});
        % Check that worked
        if isnan(temp)
            out.error = 1;
			out.message = ['validate_v3_Cl36.m: Un-numericalizable shielding value - line ' int2str(s_lines_nums(a))];
            return;
        end
		% test for bounds
        if (temp < 0) || (temp > 1)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Shielding correction out of range - line ' int2str(s_lines_nums(a))];
            return;
        end
		% Assign
		out.s.othercorr(a) = temp; clear temp;
    else
		% fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Illegal characters in shielding correction - line ' int2str(s_lines_nums(a))];
        return;
    end
    
    % 9. Erosion rate
	
	if isempty(regexp(thisline{9},'[^\d.eE+-]','once'))
		% pass
        % Convert to number
        temp = str2double(thisline{9});
        % Check that worked
        if isnan(temp)
            out.error = 1;
			out.message = ['validate_v3_Cl36.m: Un-numericalizable erosion rate value - line ' int2str(s_lines_nums(a))];
            return;
        end
		% test for bounds
        if (temp < 0)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Erosion rate less than zero - line ' int2str(s_lines_nums(a))];
            return;
        end
		% Assign
		out.s.E(a) = temp; clear temp;
	else
		% fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Illegal characters in erosion rate - line ' int2str(s_lines_nums(a))];
        return;
	end
    
    % 10. Year of sample collection
	
    if isempty(regexp(thisline{10},'[^\d]','once')) % Only allow digits
		% pass
        % Convert to number
        temp = round(str2double(thisline{10}));
        
        % Check that worked
        if isnan(temp)
            out.error = 1;
			out.message = ['validate_v3_Cl36.m: Un-numericalizable collection year value - line ' int2str(s_lines_nums(a))];
            return;
        end
		% various bounds tests and insert default for zeros
        todays_date = datevec(date);
        if (temp > todays_date(1))
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Collection year is in the future - line ' int2str(s_lines_nums(a))];
            return;
        end
        
        if (temp == 0)
            % Set default
            temp = consts.default_yr; 
        end
        
        if (temp < 1700)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Collection year out of reasonable bounds - line ' int2str(s_lines_nums(a))];
        end
            
		% Assign
		out.s.yr(a) = temp; clear temp;
    else
		% fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Illegal characters in collection year - line ' int2str(s_lines_nums(a))];
        return;
    end
    
    clear parsed_text;
end

%% Step 4. Process nuclide concentration data lines. 

for a = 1:length(cl36_lines)
    % Parse
    % Get line
    thisline = cl36_lines{a};
    
    % 1. Sample name is already validated upstream
	
    out.n.sample_name{a} = thisline{1};
       
    % Determine which sample to match
    %out.s.sample_name;
    %out.n.sample_name{a};
    temp_index = find(strcmp(out.s.sample_name,out.n.sample_name{a}));
    
    % Error on fail
    if isempty(temp_index)
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Can''t match line ' int2str(cl36_lines_nums(a)) ' to sample'];
        return;
    end
    % Error on match more than one
    if length(temp_index) > 1
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Line ' int2str(cl36_lines_nums(a)) ' appears to match more than one sample'];
        return;
    end
    % Pass, assign index number
    out.n.index(a) = temp_index;
    % Put in nuclide ID in case needed some other time
    out.n.nuclide{a} = 'Cl-36';
    
    % Check for length
    if length(thisline) ~= 6
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Wrong number of elements in Cl-36 line ' int2str(cl36_lines_nums(a))];
        return;
    end
               
    % N36

    if isempty(regexp(thisline{3},'[^\d.eE+-]','once'))
        % pass
        % Convert to number
        temp = str2double(thisline{3});
        % Check that worked
        if isnan(temp)
            out.error = 1;
            out.message = ['validate_v3_Cl-36.m: Un-numericalizable Cl-36 concentration - line ' int2str(cl36_lines_nums(a))];
            return;
        end
        % test for bounds
        if (temp <= 0)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Cl-36 concentration less than or equal to zero - line ' int2str(cl36_lines_nums(a))];
            return;
        end
        
        out.n.N(a) = temp; 
        clear temp;
    else
        % fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Unknown characters in Cl-36 concentration - line ' int2str(cl36_lines_nums(a))];
        return;
    end
        
    % delN36

    if isempty(regexp(thisline{4},'[^\d.eE+-]','once'))
        % pass
        % Convert to number
        temp = str2double(thisline{4});
        % Check that worked
        if isnan(temp)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Un-numericalizable Cl-36 uncertainty - line ' int2str(cl36_lines_nums(a))];
            return;
        end
        % test for bounds
        if (temp <= 0)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Cl-36 uncertainty less than or equal to zero - line ' int2str(cl36_lines_nums(a))];
            return;
        end
        
        out.n.delN(a) = temp; 
        clear temp;
    else
        % fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Illegal characters in Cl-36 uncertainty - line ' int2str(cl36_lines_nums(a))];
        return;
    end
     
    % [Cl]

    if isempty(regexp(thisline{5},'[^\d.eE+-]','once'))
        % pass
        % Convert to number
        temp = str2double(thisline{5});
        % Check that worked
        if isnan(temp)
            out.error = 1;
            out.message = ['validate_v3_Cl-36.m: Un-numericalizable [Cl] - line ' int2str(cl36_lines_nums(a))];
            return;
        end
        % test for bounds
        if (temp <= 0)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: [Cl] less than or equal to zero - line ' int2str(cl36_lines_nums(a))];
            return;
        end
        
        out.n.Cl(a) = temp; 
        clear temp;
    else
        % fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Unknown characters in [Cl] - line ' int2str(cl36_lines_nums(a))];
        return;
    end
    
    % del[Cl]

    if isempty(regexp(thisline{6},'[^\d.eE+-]','once'))
        % pass
        % Convert to number
        temp = str2double(thisline{6});
        % Check that worked
        if isnan(temp)
            out.error = 1;
            out.message = ['validate_v3_Cl-36.m: Un-numericalizable [Cl] uncertainty - line ' int2str(cl36_lines_nums(a))];
            return;
        end
        % test for bounds
        if (temp <= 0)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: [Cl] uncertainty less than or equal to zero - line ' int2str(cl36_lines_nums(a))];
            return;
        end
        
        out.n.delCl(a) = temp; 
        clear temp;
    else
        % fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Unknown characters in [Cl] uncertainty - line ' int2str(cl36_lines_nums(a))];
        return;
    end
        
    clear parsed_text;
end

%% Step 5. Validate and sort independent age lines. 

for a = 1:length(t_lines)

    % Get line
    thisline = t_lines{a};
    
    % 1. Sample name is already validated
	
    temp_sample_name = thisline{1};
    
    % Determine which sample to match
    %out.s.sample_name;
    %out.n.sample_name{a};
    this_sample_index = find(strcmp(out.s.sample_name,temp_sample_name));
    
    % Error on fail
    if isempty(this_sample_index)
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Can''t match formation age line ' int2str(t_lines_nums(a)) ' to sample'];
        return;
    end
    % Error on match more than one
    if length(this_sample_index) > 1
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Formation age line ' int2str(t_lines_nums(a)) ' appears to match more than one sample'];
        return;
    end
    
    % Check for length
    if length(thisline) ~= 4
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Wrong number of elements in formation age line ' int2str(t_lines_nums(a))];
        return;
    end

    %  rock age (Ma)

    if isempty(regexp(thisline{3},'[^\d.eE+-]','once'))
        % pass
        % Convert to number
        temp = str2double(thisline{3});
        % Check that worked
        if isnan(temp)
            out.error = 1;
            out.message = ['validate_v3_Cl-36.m: Un-numericalizable formation age - line ' int2str(t_lines_nums(a))];
            return;
        end
        % test for bounds
        if (temp < 0)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: formation age less than zero - line ' int2str(t_lines_nums(a))];
            return;
        end
        
        out.s.rock_age_Ma(this_sample_index) = temp; 
        clear temp;
    else
        % fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Unknown characters in formation age - line ' int2str(t_lines_nums(a))];
        return;
    end
    
    %  uncert in age (Ma)

    if isempty(regexp(thisline{4},'[^\d.eE+-]','once'))
        % pass
        % Convert to number
        temp = str2double(thisline{4});
        % Check that worked
        if isnan(temp)
            out.error = 1;
            out.message = ['validate_v3_Cl-36.m: Un-numericalizable formation age uncertainty - line ' int2str(t_lines_nums(a))];
            return;
        end
        % test for bounds
        if (temp < 0)
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: formation age uncertainty less than zero - line ' int2str(t_lines_nums(a))];
            return;
        end
        
        out.s.delrock_age_Ma(this_sample_index) = temp; 
        clear temp;
    else
        % fail
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Unknown characters in formation age uncertainty - line ' int2str(t_lines_nums(a))];
        return;
    end
    clear parsed_text;
end   

lines = [];

%% Step 6. Validate and sort major element lines.
% Note at present this assumes there is either (i) one WR and
% one target ME line, or (ii) one WR ME line, for each Cl-36 measurement.
% And then there is supposed to be only one Cl-36 measurement for each
% sample. If there are two WR ME lines, or two target ME lines, with the
% same sample name, the second one will just overwrite the first one. 

for a = 1:out.nummes
    % Parse
    % Get line
    parsed_text = me_lines{a};
    if verboseFlag; disp(['Starting new ME line: ' parsed_text{1} ' ' parsed_text{2}]);end
    
    % 1. Sample name is already validated
	
    temp_sample_name = parsed_text{1};
    
    % Determine which entry in out.n to match. Assumes there already is one
    % from processing the Cl-36 lines. 
    this_sample_index = find(strcmp(out.n.sample_name,temp_sample_name));

    % Error on fail
    if isempty(this_sample_index)
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Can''t match major element line ' int2str(me_lines_nums(a)) ' to Cl-36 line by sample name.'];
        return;
    end
    % Error on match more than one
    % This might need to be turned off in some future
    % multiple-analyses-per-sample scenario.
    if length(this_sample_index) > 1
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Major element line ' int2str(me_lines_nums(a)) ' appears to match more than one Cl-36 line'];
        return;
    end
    
    % Now determine if this is WR or target. 
    
    if strcmp(parsed_text{3},'target')
        isWR = 0;
    elseif strcmp(parsed_text{3},'WR')
        isWR = 1;
    else
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Major element line ' int2str(me_lines_nums(a)) ' is neither WR or target'];
        return;
    end
    
    % Now go through remaining fields and populate weight-percent-element
    % vectors. Remember LOI case is different.  
    
    % Now go through remaining fields and populate weight-percent-element
    % vectors
    % fields are sample_name, "major_elements", WR/target, then elt/conc pairs or elt/conc/uncert triplets
    item = 4; % start with first elt name
    two_items_flag = 0;
    eltnum = 0;
    LOIflag = 0;
    while 1
        this_item = parsed_text{item};
        if verboseFlag;disp(this_item);end
  
        % Determine whether field matches element name
        eltmatch = find(strcmp(this_item,consts.elts));
        
        if isempty(eltmatch) && ~isempty(regexp(this_item,'[^\d.eE+-]','once')) 
            % Case not a number, but element not in list of needed elements.
            okEltFlag = 0;
            
            two_items_flag = 0;
            if strcmp(this_item,'LOI')
                LOIflag = 1;
                if verboseFlag;disp(['Found LOI in item ' int2str(item)]);end
            else
                if verboseFlag;disp(['Found unnecessary element: ' this_item]);end
            end
        elseif isempty(eltmatch)
            % Case not in list of needed elements, but is a number
            % Conclude is a numerical concentration. 
            if verboseFlag; disp(['Found number: ' this_item]); end
            if eltnum == 0 && LOIflag == 0
                % Case element has not been defined
                if verboseFlag; disp(['Item ' int2str(item) ' is number with no defined element']);end;
                out.error = 1;
                out.message = ['validate_v3_Cl-36.m: Can''t assign number to element - line ' int2str(me_lines_nums(a))];
                return;
            end
            if isempty(regexp(this_item,'[^\d.eE+-]','once'))
                % If we got here, an element number is defined and we are
                % processing a numerical value. 
                % And the value passes regexp test.
                % Convert to number
                temp = str2double(this_item);
                % Check that worked
                if isnan(temp)
                    out.error = 1;
                    out.message = ['validate_v3_Cl-36.m: Un-numericalizable major element concentration - line ' int2str(me_lines_nums(a))];
                    return;
                end
                % test for bounds
                if (temp < 0)
                    out.error = 1;
                    out.message = ['validate_v3_Cl36.m: Major element concentration or uncert less than zero - line ' int2str(me_lines_nums(a))];
                    return;
                end
                % If we got this far, we have a number
                if verboseFlag; disp(['Found number ' num2str(temp)]);end
                
                % Deal with LOI case
                if LOIflag == 1
                    if two_items_flag == 0
                        if verboseFlag; disp('Placing number in LOI field');end
                        out.n.LOI(this_sample_index) = temp;
                        LOIflag = 0; % reset
                    elseif two_items_flag == 1
                        if verboseFlag; disp('LOI uncertainty not used');end
                    elseif two_items_flag > 1
                        out.error = 1;
                        out.message = ['validate_v3_Cl36.m: Too many numbers in a row - line ' int2str(me_lines_nums(a))];
                        return;
                    end
                end
                    
                % It's OK, place it in vector
                if two_items_flag == 0
                    % Case it's a concentration
                    % Note converting weight percent to weight fraction
                    if okEltFlag == 1
                        if isWR == 1
                            if verboseFlag; disp(['Placed in WR ' consts.elts{eltmatch} ' concentration, index ' int2str(eltnum)]);end
                            if verboseFlag; disp(['Command: out.n.wpe{' int2str(this_sample_index) '}(' int2str(eltnum) ') = ' num2str(temp) ';']);end
                            out.n.wpe{this_sample_index}(eltnum) = temp./100;
                        elseif isWR == 0
                            if verboseFlag; disp(['Placed in target ' consts.elts{eltmatch} ' concentration, index ' int2str(eltnum)]); end
                            if verboseFlag; disp(['Command: out.n.wpetarget{' int2str(this_sample_index) '}(' int2str(eltnum) ') = ' num2str(temp) ';']); end
                            out.n.wpetarget{this_sample_index}(eltnum) = temp./100;
                        end
                        
                    else
                        if verboseFlag; disp('Not processing concentration as an element');end
                    end
                    two_items_flag = two_items_flag + 1;
                    if verboseFlag; disp('incrementing two_items_flag');end
                elseif two_items_flag == 1
                    % Case it's an uncertainty
                    % Note converting weight percent to weight fraction
                    if okEltFlag == 1
                        if isWR == 1
                            if verboseFlag; disp(['Placed in WR ' consts.elts{eltmatch} ' uncertainty, index ' int2str(eltnum)]);end
                            out.n.delwpe{this_sample_index}(eltnum) = temp./100;
                        elseif isWR == 0
                            if verboseFlag; disp(['Placed in target ' consts.elts{eltmatch} ' uncertainty, index ' int2str(eltnum)]);end
                            out.n.delwpetarget{this_sample_index}(eltnum) = temp./100;
                        end
                    else
                        if verboseFlag; disp('Unknown element, skipping uncertainty');end
                    end
                    two_items_flag = two_items_flag + 1;
                elseif two_items_flag > 1
                    out.error = 1;
                    out.message = ['validate_v3_Cl36.m: Too many numbers in a row - line ' int2str(me_lines_nums(a))];
                    return;
                end   
                clear temp;
            else
                % fail
                out.error = 1;
                out.message = ['validate_v3_Cl36.m: Unknown characters in trace element concentration or uncertainty - line ' int2str(me_lines_nums(a))];
                return;
            end
        else
            % Case field text matches an element
            if isempty(eltmatch) || length(eltmatch) > 1
                out.error = 1;
                out.message = ['validate_v3_Cl36.m: Unmatched or overmatched trace element ID - line ' int2str(me_lines_nums(a))];
                return; 
            end
            if verboseFlag; disp(['Matched element: ' consts.elts{eltmatch} ', number ' int2str(eltmatch)]); end
            eltnum = eltmatch;
            two_items_flag = 0;
            if verboseFlag; disp('Setting two_items_flag to 0');end
            okEltFlag = 1;
        end
        
        % Go to next item
        item = item + 1;
        if verboseFlag; disp(['Moving on to item ' int2str(item)]);end
        if item > length(parsed_text)
            % End of line
            if verboseFlag; disp('No more items, stopping loop');end
            break;
        end
        if item > 100
            if verboseFlag; disp('Runaway loop');end
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Runaway loop in line ' int2str(me_lines_nums(a))];
            return;
        end
    end
    clear parsed_text;
end

%% Step 7. Validate and sort trace element lines.
% Same thing -- assuming one trace element line per sample. 

for a = 1:out.numtes    
    % Get line
    parsed_text = te_lines{a};
    if verboseFlag; disp(['Starting TE line: ' parsed_text{1} ' ' parsed_text{2}]);end
    
    
    % Sample name is already validated
	
    temp_sample_name = parsed_text{1};
    
    % Determine which entry in out.n to match
    this_sample_index = find(strcmp(out.n.sample_name,temp_sample_name));
    % In some future multiple-analyses-per-sample scenario, this will come
    % up with more than one result, and it'll be necessary to figure out
    % which one to use. 
    
    % Error on fail
    if isempty(this_sample_index)
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Can''t match trace element line ' int2str(te_lines_nums(a)) ' to Cl-36 line.'];
        return;
    end
    % Error on match more than one
    % Again, this might need to be turned off in future.
    if length(this_sample_index) > 1
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: Trace element line ' int2str(te_lines_nums(a)) ' appears to match more than one Cl-36 line'];
        return;
    end
     
    % Now go through remaining fields and populate weight-percent-element
    % vectors
    % NEEDS TO BE CHECKED AND HAVE DIAGNOSTIC TEXT REMOVED 
    item = 3; % start with third field
    two_items_flag = 0;
    eltnum = 0;
    while 1
        this_item = parsed_text{item};
        if verboseFlag; disp(this_item); end
        eltmatch = find(strcmp(this_item,consts.elts));
        
        
        if isempty(eltmatch) & ~isempty(regexp(this_item,'[^\d.eE+-]','once'))
            % Case element not in list of needed elements.
            okEltFlag = 0;
            if verboseFlag; disp(['Found unnecessary element: ' this_item]);end
            two_items_flag = 0;
        elseif isempty(eltmatch)
            % Case it's a numerical concentration. 
            if verboseFlag; disp(['Found number: ' this_item]);end
            if eltnum == 0
                out.error = 1;
                out.message = ['validate_v3_Cl-36.m: Unmatched element - line ' int2str(te_lines_nums(a))];
                return;
            end
            if isempty(regexp(this_item,'[^\d.eE+-]','once'))
                % pass
                % Convert to number
                temp = str2double(this_item);
                % Check that worked
                if isnan(temp)
                    out.error = 1;
                    out.message = ['validate_v3_Cl-36.m: Un-numericalizable trace element concentration - line ' int2str(te_lines_nums(a))];
                    return;
                end
                % test for bounds
                if (temp < 0)
                    out.error = 1;
                    out.message = ['validate_v3_Cl36.m: Trace element concentration or uncert less than zero - line ' int2str(te_lines_nums(a))];
                    return;
                end
                % It's OK, place it in vector
                if two_items_flag == 0
                    % Case it's a concentration
                    if okEltFlag == 1
                        if verboseFlag; disp(['Placed in ' consts.elts{eltmatch} ' concentration, index ' int2str(eltnum)]);end
                        if verboseFlag; disp(['Command: out.n.wpe{' int2str(this_sample_index) '}(' int2str(eltnum) ') = ' num2str(temp.*1e-6) ';']);end
                        out.n.wpe{this_sample_index}(eltnum) = temp.*1e-6;
                    else
                        if verboseFlag; disp('Skipping concentration');end
                    end
                    two_items_flag = two_items_flag + 1;
                elseif two_items_flag == 1
                    % Case it's an uncertainty
                    if okEltFlag == 1
                        if verboseFlag; disp(['Placed in ' consts.elts{eltmatch} ' uncertainty, index ' int2str(eltnum)]);end
                        out.n.delwpe{this_sample_index}(eltnum) = temp.*1e-6;
                    else
                        if verboseFlag; disp('Skipping uncertainty');end
                    end
                    two_items_flag = two_items_flag + 1;
                elseif two_items_flag > 1
                    out.error = 1;
                    out.message = ['validate_v3_Cl36.m: Too many numbers in a row - line ' int2str(te_lines_nums(a))];
                    return;
                end  
                clear temp;
            else
                % fail
                out.error = 1;
                out.message = ['validate_v3_Cl36.m: Unknown characters in trace element concentration or uncertainty - line ' int2str(te_lines_nums(a))];
                return;
            end
        else
            % Case it matches an element
            if isempty(eltmatch) || length(eltmatch) > 1
                out.error = 1;
                out.message = ['validate_v3_Cl36.m: Unmatched or overmatched trace element ID - line ' int2str(te_lines_nums(a))];
                return; 
            end
            if verboseFlag; disp(['Matched element: ' consts.elts{eltmatch} ', number ' int2str(eltmatch)]); end
            eltnum = eltmatch;
            two_items_flag = 0;
            okEltFlag = 1;
        end
        
        % Go to next item
        item = item + 1;
        if verboseFlag; disp(['Going to next item:' int2str(item) ]);end
        if item > length(parsed_text)
            % End of line
            if verboseFlag; disp('Stopping loop');end
            break;
        end
        if item > 100
            out.error = 1;
            out.message = ['validate_v3_Cl36.m: Runaway loop in line ' int2str(te_lines_nums(a))];
            return;
        end
    end
    clear parsed_text;
end


%% Step 8. Some checks for missing data and feasibility. 

% Check to make sure each sample has exactly one Cl-36 analysis

for a = 1:out.numsamples
    isCl36 = find(out.n.index == a);
    if length(isCl36) > 1
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: too many Cl-36 data for sample ' int2str(a)];
        return
    elseif isempty(isCl36)
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: no Cl-36 data for sample ' int2str(a)];
        return
    end
end

% Check to make sure there are some chemistry data for all samples

for a = 1:out.numsamples
    ischem = find(out.n.wpe{a} > 0.01);
    if isempty(ischem)
        out.error = 1;
        out.message = ['validate_v3_Cl36.m: is there any chem data for sample ' int2str(a) '?'];
    end
end








