function  cache = cache_inputs(Idef,job_descr,P)

%CACHE_INPUTS -- Call PLFRONTEND on many stimuli and cache the results.
%
%  cache = cache_inputs(Idef,job_descr)
%  cache = cache_inputs(Idef,job_descr,P)
%
%  IDEF is a "front-end definition structure" produced by MAKE_PLFRONTEND.
%  P is a "stimulus parameter struct" produced by PLEXP1_PARAMS. Optional.
%  JOB_DESCR is either an integer or a struct with the following fields:
%   1. N -- number of replications of each stimulus class
%   2. block -- number of passes through conditions considered a "block"
%   3. fname -- file name for saving the (partial) CACHE at the end of
%        each block. The empty string means "Don't save."
%        If this field is missing, it defaults to ['cache-' date].
%        That is, CACHE_INPUTS saves the intermediate results by default
%        using fnames such as 'cache-04-Jun-2002.mat' in the current dir.
%   4. verbose -- fileid for verbose messages, 0=don't, default=1=stdout
%   5. cache -- a structure (see below)
%  When only a number is supplied for JOB_DESCR, it specifies the number
%  of replications N and the remaining fields are filled in with
%  defaults: block=20, cache=[2x3x2 struct] with N=0 and correspondingly
%  initialized 'arg' fields ([1 1 1], [2 1 1], [1 2 1], etc.)
%
%  The resulting CACHE is a structure with the following fields:
%   1. arg -- three-element vector with MAKE_PLE_STIM arguments
%   2. N -- number of valid entries calculated so far
%   3. rep -- a matrix with JOB_DESCR.N rows and N_REP columns.
%
%  For each "replication" K, the following sequence is executed:
%    for  cond = 1:12
%     arg=cache(cond).arg ; stim=make_PLE_stim(P,arg(1),arg(2),arg(3));
%     rep = PLFrontend(stim,Idef) ;    % <-- takes ~2 sec for [19x3]
%     cache(cond).rep(k,:) = rep ; cache(cond).N += 1 ;
%    end
%
%  Post-processing (see AGGREG_CACHE and INPUT_VARIABILITY):
%    for k = 1:length(cache)
%     N = cache(k).N ; X=cache(k).rep(1:N,:) ;    % [Nx35]
%     cache(k).mean = mean(X) ;                   % [1x35]
%     cache(k).square = (X'*X) ./ N ;             % [35x35]
%    end
%
%  See also PLFRONTEND, BLOCK_FROM_CACHE, AGGREG_CACHE, MAKE_PLE_STIM.

%  Original coding by Alexander Petrov, UC Irvine.
%  $Revision: 2.0 $  $Date: 2002/06/28 17:09 $

%-- Handle the input arguments
if (nargin<3)  P = PLExp1_params ; end  % default, virtually set in stone

if (isnumeric(job_descr))
   job_descr = struct('N',job_descr) ;
%else assume JOB_DESCR is a structure, fully or partially specified
end
N = job_descr.N ;

%-- Fill-in missing slots in JOB_DESCR
if (~isfield(job_descr,'block'))
  job_descr.block = 20 ;
end
if (~isfield(job_descr,'fname'))
  job_descr.fname = ['cache-' date] ;   % e.g. 'cache-04-Jun-2001'
end
if (~isfield(job_descr,'verbose'))
  job_descr.verbose = 1 ;       % print messages on STDOUT by default
end
if (~isfield(job_descr,'cache'))
  cache(1,1,1).arg=[1 1 1];cache(2,1,1).arg=[2 1 1];
  cache(1,2,1).arg=[1 2 1];cache(2,2,1).arg=[2 2 1];
  cache(1,3,1).arg=[1 3 1];cache(2,3,1).arg=[2 3 1];
  cache(1,1,2).arg=[1 1 2];cache(2,1,2).arg=[2 1 2];
  cache(1,2,2).arg=[1 2 2];cache(2,2,2).arg=[2 2 2];
  cache(1,3,2).arg=[1 3 2];cache(2,3,2).arg=[2 3 2];
  for k=1:12 cache(k).N=0;cache(k).rep=zeros(N,prod(Idef.rep_size));end
else
  cache = job_descr.cache ;
  %It's taken for granted that each CACHE.rep has at least N vacant rows.
end
block = job_descr.block ;
fname = job_descr.fname ;
verbose = job_descr.verbose ;
N_conditions = prod(size(cache)) ;

%-- Main loop
for  k = 1:N
   for  cond = 1:N_conditions
      arg = cache(cond).arg ;
      stim = make_PLE_stim(P,arg(1),arg(2),arg(3));
      rep = PLFrontend(stim,Idef)' ;   % <-- the time-consuming stuff
      n = cache(cond).N + 1 ;          % index of the first vacancy
      cache(cond).N = n ;
      cache(cond).rep(n,:) = rep ;
   end
   if verbose  fprintf(verbose,'.') ; end
   %- save at regular intervals or "blocks"
   if ((mod(k,block)==0)|(k==N))    % 10, 20, 30, ... or END
      if (isempty(fname))  % saving option switched off?
         if verbose  fprintf(verbose,' N=%3d\n',k) ; end
      else
         save(fname,'cache') ;  % save partial CACHE to disk
         if verbose  fprintf(verbose,...
            ' N=%3d, saved to %s.mat\n',k,fname) ;
         end
      end %if isempty(fname)
   end % if block boundary
end % for k=1:N

%--- Return CACHE
%%%%% End of file CACHE_INPUTS.M
