%_______________________________________________________________________
%
% Modified binary search (MOBS)
%_______________________________________________________________________
%
% MOBS is an adaptive, non-parametric procedure f. estimating thresholds
%_______________________________________________________________________
%
% Input
%
% dotInfo | experiment configuration (struct)
%
% Output
%
% dotInfo | experiment configuration (struct)
%_______________________________________________________________________
%
% Original publication:
%
% Tyrrell, R. A., & Owens, D. A. (1988). A rapid technique to assess the
% resting states of the eyes and other threshold phenomena: The Modified
% Binary Search (MOBS). Behavior Research Methods, Instruments & Computers,
% 20(2), 137-141. 
%
% Deviations from original specification:
%
% Turpin, A., McKendrick, A. M., Johnson, C. A., & Vingrys, A. J. (2002).
% Development of Efficient Threshold Strategies for Frequency Doubling
% Technology Perimetry Using Computer Simulation. Investigative
% Ophthalmology & Visual Science, 43(2), 322-331.
%
function dotInfo = mobs(dotInfo)

  lowStack = dotInfo.lowStack;
  highStack = dotInfo.highStack;

  coh = dotInfo.coh;
  resp = dotInfo.resp;
  consecIdent = dotInfo.consecIdent;

  % response based on short-term accuracy for increasing/decreasing coherence
  longResp = dotInfo.longResp;
  lastLongResp = dotInfo.lastLongResp;

  % response based on stable mid-term accuracy for deciding about regressions
  lastResp = dotInfo.lastResp;

  % count consecutive identical responses based on mid-term accuracy
  if numel(longResp) > 0 && strcmp(longResp,lastLongResp)
    consecIdent = consecIdent + 1;
  else
    consecIdent = 0;
  end

  % if the last and second to last step had the same response and the
  % response to the current level differs from an earlier response
  % to the same level then we perform a "regression" meaning that
  % the top element of the stack where the current value was taken
  % from is removed, the remaining two elements moved up and the
  % blank space is filled up with the initial value of that stack
  %
  if consecIdent > 1 && mod(consecIdent,2) == 0
    if strcmp(lastResp,'yes')
      lowStack = lowStack.regress;
      dotInfo.regress = 'low';
    else
      highStack = highStack.regress;
      dotInfo.regress = 'high';
    end
  else
    dotInfo.regress = false;
  end

  % the current coherence level is pushed to the top of the appropriate
  % stack resulting in the lower elements being shifted downwards and the
  % bottom element being removed. This deviates from the original algorithm
  % but conforms to Turpin et al (2002) referenced above
  %
  if strcmp(resp,'yes')
    highStack = highStack.insert(coh);
  else
    lowStack = lowStack.insert(coh);
  end
  
  % we choose the new coherence level to be midway
  % between the top element of the low and high stack
  %
  coh = (lowStack.top + highStack.top)/2;

  dotInfo.lastResp = resp;
  dotInfo.lastLongResp = longResp;
  dotInfo.consecIdent = consecIdent;
  dotInfo.lowStack = lowStack;
  dotInfo.highStack = highStack;
  dotInfo.coh = coh;

end
