

function varargout = Chromatic_Integration_Contrast_Order(pulsenumbers, varargin)
%
%
%%% Chromatic_Integration_Contrast_Order %%%
%
%
% This function returns the stimulus order and contrast values for the defined
% numbers of input pluses. It uses Fisher-Yates random permutation to set the
% stimulus order. For more info, see the function fisher_Yates_shuffle_order
% below.
%
% ===============================Inputs====================================
%
%   pulsenumbers    :   number of stimulus pulses.
%
% =========================Optional Inputs=================================
%
% selecttextfile        false       Browse prompt to select the parameters text file
% stimduration          30          Stimulus presentation duration screen refresh rate unit (30 = 0.5 sec)
% preframes             120         Duration of background light presented in between the stimulus flashes
% maxcontrast           0.2         Maximum Weber contrast value (ranges from -1 to 1)
% mincontrast          -0.2         Minimum Weber contrast value (ranges from -1 to 1)
% contrastdiff          0.02        Contrast steps from mincontrast to maxcontrast e.g. -20 : 2 : 20
% seed                  -1000   	Starting value for random number generator (should be always negative)
% redmeanintensity        0     	Mean intensity for red gun of the screen
% greenmeanintensity	0.5         Mean intensity for green gun of the screen
% bluemeanintensity     0.5     	Mean intensity for blue gun of the screen
% help                  false       Option to check the list of available parameters
%
%================================Output====================================
%
%   varargout{1}    :   stimulus order, green contrasts and blue contrasts.
%   varargout{2}    :   stimulus order.
%
% written by Mohammad, 12.02.2021

para            =   read_stimulus_parameters(varargin{:});
if para.help, return; end

offcontrasts    =   fliplr(0:-para.contrastdiff:para.mincontrast);
oncontrasts     =   0:para.contrastdiff:para.maxcontrast;
numcontrasts    =   length(oncontrasts)*2;
% generating contrast values
if numel(pulsenumbers) > 1
    para.numtrials      =       floor( length( pulsenumbers(2 : 2 : numel(pulsenumbers))) / numcontrasts );
else
    para.numtrials      =       floor( pulsenumbers/2 / numcontrasts ); % 1 pulse for stimulus, one for preframe
end
seed                    =       para.seed;
stimorder               =       nan(para.numtrials, numcontrasts);

% getting the order and location of each contrast from the psudo random sequence
for ii      =   1 : para.numtrials
    [stimorder(ii,:),seed,~]    =   fisher_Yates_shuffle_order(seed, 1:numcontrasts);
end

% setting up output to get the stimulus order contrast orders
stimorder     =   stimorder';     % transposing to make vectorization (:) easier
stimorder     =   stimorder(:);
% out.numberContrastsShown = floor((framecounter-1)/(para.stimduration+para.preframes));
% stimorder     =   stimorder(1:out.numberContrastsShown);
out.stimulusOrder   =   transpose(stimorder);
% to get contrasts between input values
greencontrasts      =   [offcontrasts,oncontrasts];
bluecontrasts       =   [oncontrasts,offcontrasts];
% convert to weber contrast (mean+(contrast*mean))
greencontrasts  =   para.greenmeanintensity + (greencontrasts * para.greenmeanintensity);
bluecontrasts   =   para.bluemeanintensity + (bluecontrasts * para.bluemeanintensity);
% set the contrast output
out.greenContrasts  =   greencontrasts(stimorder);
out.blueContrasts   =   bluecontrasts(stimorder);
out.trialnumbers    =   para.numtrials;

varargout{1}        =   out;
varargout{2}        =   stimorder;

end

%--------------------------------------------------------------------------------------------------%
%----------                               sub-functions                                  ----------%
%--------------------------------------------------------------------------------------------------%


function varargout = fisher_Yates_shuffle_order(seed,inputVec,varargin)
%
%%% fisher_Yates_shuffle_order %%%
%
%
% This function generate psudorandom permution similar to randperm in MATLAB
% but works with psudorandom number generator ran1. It also gives back the
% most recent seed value to continue the permuation in case of repeated trials.
% note that the direction of permutation is along x-axix or for columns of
% MATALB not for the rows.
%
%
% ===============================Inputs====================================
%
%   seed : seed value for random number generation.
%   inputVec : input vector used for permutation.
%
%================================Output====================================
%
%   testOrder : vector of permuted indices for the inputVec.
%   newSeed : the recent seed that used in the ran1 function.
%   outputVec : the permuted input vector along x-axis
%
% Note that the permution algorithem is based on Fisher-Yates shuffle
% algorithem identical to what is used in the stimulus program.
% for more info check :
% https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
%
% written by Mohammad, 01.02.2016

newSeed         =   seed;
testOrder       =   zeros(1,size(inputVec,2));
testOrder(1)    =   1;

for i   =   2:length(inputVec)-1
    
    [randVal,newSeed] = ran1(newSeed);
    
    j               =   ceil(i*randVal);    % based on Fischer-Yates algorithem
    testOrder(i)    =   testOrder(j);
    testOrder(j)    =   i;
    
end

testOrder           =   [testOrder(end),testOrder(1:end-1)]+1;   % to match MATLAB indexing
varargout{1}        =   testOrder;
varargout{2}        =   newSeed;
for j   =   1:size(inputVec,1)
    varargout{3}(j,:)   =   inputVec(j,testOrder);
end

end

%--------------------------------------------------------------------------------------------------%

function paraout = read_stimulus_parameters(varargin)

% first parse the user inputs
p = inputParser();      % check the user options.
p.addParameter('selecttextfile', false,  @(x) islogical(x) || (isnumeric(x) && ismember(x,[0,1])));
p.addParameter('stimduration', 30, @isnumeric);
p.addParameter('preframes', 120, @isnumeric);
p.addParameter('contrastdiff', 0.02, @isnumeric);
p.addParameter('mincontrast',-0.2, @isnumeric);
p.addParameter('maxcontrast', 0.2, @isnumeric);
p.addParameter('seed', -1000, @isnumeric);
p.addParameter('redmeanintensity', 0, @isnumeric);
p.addParameter('greenmeanintensity', 0.5, @isnumeric);
p.addParameter('bluemeanintensity', 0.5, @isnumeric);
p.addParameter('help', false,  @(x) islogical(x) || (isnumeric(x) && ismember(x,[0,1])));

p.parse(varargin{:});
% defualt parameters
defpara     =    p.Results;

if defpara.help
    help_info_for_parameters(defpara);
    paraout     =   defpara;
    return;
end

if defpara.selecttextfile
    % now read the text files
    [stimfile, stimpath] = uigetfile('*.txt','Select a chromatic integration stimulus parameter file','chromatic_integration.txt');
    
    fid     =   fopen([stimpath,filesep,stimfile]);
    tline   =   fgetl(fid);
    while ischar(tline)
        tline   =   fgetl(fid);
        if tline == -1, break; end
        fn      =   extractBefore(tline,' = ');
        if isempty(fn), continue; end
        val     =   extractAfter(tline,' = ');
        % to convert to double
        if ~isnan(str2double(val))
            val =   str2double(val);
        end
        % to convert to logical
        if strcmp(val,'true'),        val = true;       end
        if strcmp(val,'false'),       val = false;       end
        % store the values in a structure
        stimpara.(fn)   =   val;
    end
    fclose(fid);
    
    % compare the text file to the defualt values and fill the missing parameters
    fn      =       fieldnames(defpara);
    for ii  =   1:numel(fn)
        if isfield(stimpara,fn{ii})
            paraout.(fn{ii})    =       stimpara.(fn{ii});
        else
            paraout.(fn{ii})    =       defpara.(fn{ii});
        end
    end
else
    paraout     =       defpara;
end

end

%--------------------------------------------------------------------------------------------------%

function help_info_for_parameters(defpara)

fn          =   fieldnames(defpara);
fprintf(['\n\n',repmat('==',1,50),'\r\n']);
fprintf([repmat(' ',1,35),'List of Stimulus Parameters\r\n']);
fprintf([repmat('==',1,50),'\r\n']);
maxtxtlen   =   max(cellfun(@numel,fn))+10;
for ii      =  1:numel(fn)
    g       =  repmat(' ',1,maxtxtlen - numel(fn{ii}));
   fprintf(['\t-- \t%s',g,':',repmat(' ',1,10),'%s\n'],fn{ii},num2str(defpara.(fn{ii}))); 
end
fprintf(['\n',repmat('==',1,50),'\r\n']);

end 
