

function SpatioTemporal_Binary_White_Noise_Stimulus(varargin)
%
%
%===================================================================================
% Parameter             Default                         Usage
%===================================================================================
%
% selecttextfile       	false       To call browse prompt to select the parameters text file
% stixelwidth           6           Width of each pixel of the checkerboard defined in monitor pixels unit
% stixelheight          6           Height of each pixel of the checkerboard defined in monitor pixels unit
% blackwhite            true        Option to switch between Binary and Gaussian white-noise (Not available)
% contrast              1           Contrast of black & white stimulus. 1 is 100 contrast.
% meanintensity         0.5         Mean intensity value used to define contrast
% seed                  -1000       Starting value for random number generator (should be always negative)
% secondseed            -10000  	Same as seed but for green color (only used if color is true).
% thirdseed             -2000   	Same as seed but for blue color (only used if color is true).
% nblinks               2           Number of frames to hold the stimulus on screen (2 is 30 Hz stimulus)
% color                 false   	Option to switch between black & white and chromatic white-noise
% redmeanintensity  	0           Mean intensity for red gun of the screen (only used if color is true).
% greenmeanintensity	0.5         Mean intensity for green gun of the screen (only used if color is true).
% bluemeanintensity     0.5         Mean intensity for blue gun of the screen (only used if color is true).
% redcontrast           0           Contrast of red stimulus (only used if color is true).
% greencontrast         0.75        Contrast of green stimulus (only used if color is true).
% bluecontrast          0.75        Contrast of blue stimulus (only used if color is true).
% screensize            864 x 480	Screen resolution, default value is the resolution of the lightcrafter projector
% refreshrate           60      	Screen refresh rate in Hz
% fullscreen            false       Option to display the stimulus in full-screen mode
% help                  false       Option to check the list of available parameters
% lmargin               0           Margins from left side of the screen (not available for this stimulus)
% rmagin                0           Margins from right side of the screen (not available for this stimulus)
% tmargin               0       	Margins from top of the screen (not available for this stimulus)
% bmargin               0       	Margins from bottom of the screen (not available for this stimulus)
% coneisolating         false       Option to activate opsin-isolation (excluded for simplicity)
%
%====================================================================================
%
%

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

% xax = (para.lmargin+1):para.stixelwidth:(para.screensize(1)-(para.rmargin));
% yax = (para.bmargin+1):para.stixelheight:(para.screensize(2)-(para.tmargin));

xax     =   linspace(para.lmargin,para.screensize(1)-(para.rmargin),para.Nx)+para.stixelwidth/2;
yax     =   linspace(para.tmargin,para.screensize(2)-(para.bmargin),para.Ny)+para.stixelheight/2;


% The darwing of the screen goes here
monitorsize =   get(0,'ScreenSize');
scpos       =   [monitorsize(3)/2-(para.screensize(1)/2), ...
    monitorsize(4)/2-(para.screensize(2)/2), para.screensize];
% make an screen like figure
fh          =   figure('Menu','none','ToolBar','none','Position',scpos,'Color',0.5*[1 1 1]);
fh.Name     =   'Example of Spatio-temporal White Noise Stimulus, from Khani and Gollisch (2021)';
fh.Colormap =   gray;
ah          =   axes('Units','Normalize','Position',[0 0 1 1],'Color',0.5*[1 1 1]);
axis(ah,[0, para.screensize(1),0, para.screensize(2)]);
axis(ah,'off');


framecounter    =   0;
if para.color
    seed1       =   para.seed;
    seed2       =   para.secondseed;
    seed3       =   para.thirdseed;
    
    redWeberContrastHigh    = para.redmeanintensity   + (para.redContrast   * para.redmeanintensity);
    redWeberContrastLow     = para.redmeanintensity   - (para.redContrast   * para.redmeanintensity);
    greenWeberContrastHigh  = para.greenmeanintensity + (para.greenContrast * para.greenmeanintensity);
    greenWeberContrastLow   = para.greenmeanintensity - (para.greenContrast * para.greenmeanintensity);
    blueWeberContrastHigh   = para.bluemeanintensity  + (para.blueContrast  * para.bluemeanintensity);
    blueWeberContrastLow    = para.bluemeanintensity  - (para.blueContrast  * para.bluemeanintensity);
    
else
    seed        =   para.seed;
    whiteWeberContrastHigh  = para.meanintensity + (para.contrast * para.meanintensity);
    whiteWeberContrastLow   = para.meanintensity - (para.contrast * para.meanintensity);
end

while ishandle(fh)
    
    if para.color
        % red
        [checkerred, seed1]     =   ran1(seed1,para.Nx*para.Ny);
        checkerred  =   single((checkerred > para.redmeanintensity) .* redWeberContrastHigh);
        checkerred(checkerred == 0)  =   redWeberContrastLow;
        checkerred              =   reshape(checkerred,para.Ny,para.Nx);
        % green
        [checkergreen, seed2]   =   ran1(seed2,para.Nx*para.Ny);
        checkergreen =  single((checkergreen > para.greenmeanintensity) .* greenWeberContrastHigh);
        checkergreen(checkergreen == 0)     =   greenWeberContrastLow;
        checkergreen            =   reshape(checkergreen,para.Ny,para.Nx);
        % blue
        [checkerblue, seed3]    =   ran1(seed3,para.Nx*para.Ny);
        checkerblue  =  single((checkerblue > para.bluemeanintensity) .* blueWeberContrastHigh);
        checkerblue(checkerblue == 0)       =   blueWeberContrastLow;
        checkerblue             =   reshape(checkerblue,para.Ny,para.Nx);
        % put all colors together
        checker                 =   cat(3,checkerred,checkergreen,checkerblue);
    else
        % black & white checker
        [checker, seed]         =   ran1(seed,para.Nx*para.Ny);
        checker     =   single((checker > para.meanintensity) .* whiteWeberContrastHigh);
        checker(checker == 0)   =   whiteWeberContrastLow;
        checker                 =   reshape(checker,para.Ny,para.Nx);
        checker                 =   repmat(checker,1,1,3);
    end
    
    if framecounter == 0
        rf                      =   imagesc(xax,yax, checker);
        axis(ah,[0, para.screensize(1),0, para.screensize(2)]);
        set(ah,'Color',0.5*[1 1 1]); % this is to have gray background with margins
    else
        rf.CData                =   checker;
    end
    
    % this is to draw the frames relatively accurately.
    drawnow;
    java.lang.Thread.sleep(para.nblinks/para.refreshrate*1e3);
    %pause(1/para.refreshrate);
    framecounter    =   framecounter+1;
end

end

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

function paraout = read_stimulus_parameters(varargin)

% first parse the user inputs
p = inputParser();      % check the user options.

validtruefalse = @(x) islogical(x) || (isnumeric(x) && ismember(x,[0,1]));
p.addParameter('selecttextfile', false,  validtruefalse);
p.addParameter('stixelwidth', 6, @isnumeric);
p.addParameter('stixelheight', 6, @isnumeric);
p.addParameter('blackwhite', true,  validtruefalse);
p.addParameter('contrast',1, @isnumeric);
p.addParameter('meanintensity', 0.5, @isnumeric);
p.addParameter('seed', -1000, @isnumeric);
p.addParameter('secondseed', -10000, @isnumeric);
p.addParameter('thirdseed', -2000, @isnumeric);
p.addParameter('nblinks', 2, @isnumeric);
p.addParameter('lmargin',0, @isnumeric);
p.addParameter('rmargin', 0, @isnumeric);
p.addParameter('bmargin', 0, @isnumeric);
p.addParameter('tmargin', 0, @isnumeric);
p.addParameter('color', false,  validtruefalse);
p.addParameter('coneisolating', true,  validtruefalse);
p.addParameter('redmeanintensity', 0, @isnumeric);
p.addParameter('greenmeanintensity', 0.5, @isnumeric);
p.addParameter('bluemeanintensity', 0.5, @isnumeric);
p.addParameter('redContrast', 0, @isnumeric);
p.addParameter('greenContrast', 0.75, @isnumeric);
p.addParameter('blueContrast', 0.75, @isnumeric);
p.addParameter('screensize', [864 480], @isnumeric);
p.addParameter('refreshrate', 60, @isnumeric);
p.addParameter('fullscreen', false, validtruefalse);
p.addParameter('help', false,  validtruefalse);

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

% stimsize    =   [0+para.bmargin, 0+para.lmargin, para.screensize(1)-para.rmargin,...
%                 para.screensize(2)-para.tmargin];
xpixels     =   paraout.screensize(1) - (paraout.lmargin + paraout.rmargin);
ypixels     =   paraout.screensize(2) - (paraout.tmargin + paraout.bmargin);
paraout.Nx  =   ceil(xpixels / paraout.stixelwidth);
paraout.Ny  =   ceil(ypixels / paraout.stixelheight);

if paraout.stixelwidth > xpixels, paraout.stixelwidth = xpixels-1; end
if paraout.stixelheight > ypixels, paraout.stixelheight = ypixels-1; end

if paraout.fullscreen
    monitorsize         =   get(0,'ScreenSize');
    paraout.screensize  =   monitorsize(3:4) ;
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
