%_______________________________________________________________________
%
% Configuration for running dotsExperiment
%_______________________________________________________________________
%
% Output
%
% dotInfo | configuration for random dots experiment (struct)
%_______________________________________________________________________
%
function dotInfo = createDotInfo_JQK_170323

    %   dotInfo.introNumTrial = 10; % number of introduction trials per mode  
    %   dotInfo.winSize = 4; % number of trials for short-term average accuracy
    %   dotInfo.longWinSize = 8; % number of trials for mid-term average accuracy
    %   dotInfo.minCoh = 0; % minimum coherence value
    %   dotInfo.maxCoh = 800; %  maximum coherence value
    %   dotInfo.coh = 800; % coherence starting value for introduction
    %   dotInfo.targetAcc = 0.75; % targeted average accuracy for task
    
    dotInfo.dirSet          = [180, 0]; % dots in left or right direction
    dotInfo.numDotField     = 1; % show a single dot patches on screen
    dotInfo.apXYD           = [0 0 130]; % coordinates and diameter of aperture
    dotInfo.speed           = [50]; % speed of dot motion
    dotInfo.trialtype       = [2 1 1]; % reaction time, not relevant, keyboard
    dotInfo.dotSize         = 3; % dot size in pixels
    dotInfo.maxDotTime      = 2; % maximum duration of moving dots
    dotInfo.fixXY           = [0 0]; % fixation coordinates
    dotInfo.fixDiam         = 2; % fixation diameter
    dotInfo.fixColor        = [255 0 0]; % red fixation dot
    dotInfo.fixMinTime      = 0.75; % minimum fixation
    dotInfo.fixMaxTime      = 1.25; % maximum fixation
    dotInfo.maxDotsPerFrame = 300; % depends on graphics card
    dotInfo.fixTime         = 2; % JQK: fixed onset fixation time

    dotInfo.ContrastLevels   = [0 .25 .5 1];
    dotInfo.contrastBlocks   = 6;
    dotInfo.breakTime        = 15; % break after blocks in seconds
  
    dotInfo.cohLevels       = [250, 350, 500, 700];
    %dotInfo.timeTarget      = .3; % target time in s
    %dotInfo.timeNontarget   = [.3, .3, .3]; % target time in s
    dotInfo.timeTarget      = 1.9; % target time in s
    dotInfo.timeNontarget   = [3.6, 6.6, 8.4]; % target time in s
    dotInfo.repPerStim      = 6;
    
    % BG info
    dotInfo.percentOfBG = .001; % percentage of all display dots that are randomly replaced
    
    % update frequency of on-screen content
    
    dotInfo.Hz_BG   = 10; % background dots
    dotInfo.Hz_RDM  = 8; % kinematogram
    
    % multi-attribute task
    
    dotInfo.MAT.percAtt1 = .8;
    dotInfo.MAT.percAtt2 =  1-dotInfo.MAT.percAtt1; % For each attribute, the relative amount of dots for each attribute option is the same.
    dotInfo.MAT.colorMat = [255 255 255; 255 215 0]; % define dot color
    dotInfo.MAT.coherence = 1;  % define dot movement (coherence) [useless now!]
    dotInfo.MAT.directions = [180 0]; % left and right
    dotInfo.MAT.dotSize = [4 8]; % define dot size
    dotInfo.MAT.dotLum = [.4 .6]; % define dot luminance

    %% Keyboard responses
    % Use OS X keyboard naming scheme across all plattforms
    % Otherwise LeftControl/RightControl are not recognized
    KbName('UnifyKeyNames');

    if ismac % Mac keyboard
    dotInfo.keyLeft = KbName('LeftGUI'); % left cmd when dots moving to left
    dotInfo.keyRight = KbName('RightGUI'); % right cmd when dots moving to right
    else % PC keyboard
    dotInfo.keyLeft = KbName('LeftControl'); % left ctrl when dots moving to left
    dotInfo.keyRight = KbName('RightControl'); % right ctrl when dots moving to right
    end

    dotInfo.keyModifier = KbName('LeftAlt'); % to prevent accidental input
    dotInfo.keyEscape = KbName('Escape'); % exit experiment
    dotInfo.keyReturn = KbName('Return'); % continue experiment

    %% JQK additions for continuous paradigm
  
    %% define contrast blocks
            
%     allPerms = perms(dotInfo.ContrastLevels);
%     randChoice = randperm(size(allPerms,1));
%     randPerms = allPerms(randChoice,:);
%     randPermsVec = reshape(randPerms', 1,[]);
%     
%     dotInfo.checkerDuration = repmat(dotInfo.blockTime, 1,numel(randPermsVec(1:9)));
%     
%     % NOTE: This still needs an optimal matching between the coherences+
%     % directions and the blocks.
%     
%     dotInfo.Contrast = randPermsVec(1:9);
    
    % simply mirror the conditions to get staircase, allowing mirroring
    % contrast; note that this allows for ToT to not be equally distributed

    dotInfo.Contrast = [dotInfo.ContrastLevels, fliplr(dotInfo.ContrastLevels)];
    
    %% randomize stimuli and non-target duration
    
    % set random seed

    rseed = sum(100*clock);
    rng(rseed,'twister');
    [dotInfo.rngSetting] = rng;
  
    % fixed, random timing for RDM blocks

    % let's also fix coherence for now (e.g. Kelly & O'Connell, 2014)
    % 6 of each direction-coherence level

    stimAmount = numel(dotInfo.dirSet)*numel(dotInfo.cohLevels);
    
    for indBlock = 1:dotInfo.contrastBlocks % new randomization for each block
    
        distrib = repmat([1:stimAmount],1,dotInfo.repPerStim);
        tmp_rand = randperm(numel(distrib));
        distrib_rand = distrib(tmp_rand);

        dotInfo.coh{indBlock} = NaN(1,numel(distrib_rand));
        dotInfo.dir{indBlock} = NaN(1,numel(distrib_rand));
        for indDis = 1:8
            if indDis <= 4
                indDir = 1;
                indCoh = indDis;
            else
                indDir = 2;
                indCoh = indDis-4;
            end;
            curDis = find(distrib_rand==indDis);
            dotInfo.coh{indBlock}(curDis) = dotInfo.cohLevels(indCoh);
            dotInfo.dir{indBlock}(curDis) = dotInfo.dirSet(indDir);
        end;

        tmp.coh = []; tmp.dir = [];
        for indCoh = 1:numel(dotInfo.coh{indBlock})
            tmp.coh = [tmp.coh, 0, dotInfo.coh{indBlock}(indCoh)];
            tmp.dir = [tmp.dir, -1, dotInfo.dir{indBlock}(indCoh)]; % choose -1 when coherence is zero (everything should be fine, except for NaN)
        end;

        dotInfo.coh{indBlock} = tmp.coh;
        dotInfo.dir{indBlock} = tmp.dir;
    
        nonTargets = tmp.coh == 0;
        Targets = tmp.coh ~= 0; clear tmp;

        nontargetDur = repmat([1:3], 1, 16); % create vector for non-target duration
        tmp_rand = randperm(numel(nontargetDur));
        targetDur_rand = nontargetDur(tmp_rand);

        dotInfo.presTime{indBlock} = NaN(1,numel(dotInfo.coh));
        dotInfo.presTime{indBlock}(nonTargets) = dotInfo.timeNontarget(targetDur_rand);
        dotInfo.presTime{indBlock}(Targets) = dotInfo.timeTarget;

        clear nonTargets Targets;
        
        dotInfo.blockDuration(indBlock) = sum(dotInfo.presTime{indBlock});
        dotInfo.blockDuration_min(indBlock) = dotInfo.blockDuration(indBlock)/60; % ~6.5 minutes per block (see O'Connell)
        
    end;
    
    %% frequency flicker for distractor
            
    displayList = Screen('screens');
    displayIdx = displayList(1);
    PsychDebugWindowConfiguration(0, 0);
    screenInfo = openExperiment(50,50,displayIdx); clc; % open drawing canvas
    ifi = Screen('GetFlipInterval', screenInfo.curWindow);
    closeExperiment;
    
    % set flicker frequency
    checkFlipTimeSecs = 1/dotInfo.Hz_BG;

    % jitter frequency

    for indBlock = 1:dotInfo.contrastBlocks
        
        checkerDuration = sum(dotInfo.presTime{indBlock}); % length of checkerboard presentation is the total duration of the stimuli
        checkerDuration = ceil(checkerDuration+.1*checkerDuration); % pad a bit so that slight timing problems do not become an issue; NOTE that this may slightly affect the average flicker frequency, but shouldn't be too bad.
        flipsAtMeanFreq = checkFlipTimeSecs/ifi; 
        rangeOfUpdates = flipsAtMeanFreq-2:1:flipsAtMeanFreq+2; % range of refresh intervals
        repPerUpdate = checkerDuration/sum(rangeOfUpdates.*ifi); % round up checker duration to be safe and to make repmat work
        Updates = repmat(rangeOfUpdates, 1, repPerUpdate);
        
        randUpdate = [];
        randUpdate = randperm(numel(Updates));
        dotInfo.UpdatesJitter{indBlock} = Updates(randUpdate); % contains the frame numbers at which an inversion occurs
    end;
    
end
