function [ MotionData ] = preprocess2( MotionData, CDBNConfig )
% Version 2.0 
%
% Modified as a function by Omid Alemi
%
% Code provided by Graham Taylor, Geoff Hinton and Sam Roweis 
%
% For more information, see:
%     http://www.cs.toronto.edu/~gwtaylor/publications/nips2006mhmublv
%
% Permission is granted for anyone to copy, use, modify, or distribute this
% program and accompanying programs and documents for any purpose, provided
% this copyright notice is retained and prominently displayed, along with
% a note saying that the original programs are available from our
% web page.
% The programs and documents are distributed without any warranty, express or
% implied.  As the programs were written for research purposes only, they have
% not been tested to the degree that would be advisable in any important
% application.  All use of these programs is entirely at the user's own risk.
%
% We support two types of skeletons:
%  1) Those built from the CMU database (acclaim)
%     http://mocap.cs.cmu.edu/
%  2) Those built from data from Eugene Hsu (mit)
%     http://people.csail.mit.edu/ehsu/work/sig05stf/
% This program preprocesses data (stage 2 of 2)
% We extract the dimensions of interest and form "mini-batches"
% We also scale the data.
% Certain joint angles are 1-2 DOF, so don't model constant zero cols
%

clear batchdata minibatchdata batchdataindex
        %size of minibatches
numvalidatebatches = 0; %num of minibatches to use for the validation set

clear seqlengths;

if strcmp(MotionData.skel.type,'acclaim')
 %CMU-style data
 %No offsets, but several dimensions are constant 
 indx = [ 1:6 ...        %root (special representation)
   10:12 13 16:18 19 ... %lfemur ltibia lfoot ltoes
   25:27 28 31:33 34 ... %rfemur rtibia rfoot rtoes
   37:39 40:42 43:45 46:48 49:51 52:54 ... %lowerback upperback thorax lowerneck upperneck %head
   58:60 61 65 67:69 73:75 ... %(lclavicle ignored) lhumerus lradius lwrist lhand (fingers are constant) lthumb
   79:81 82 86 88:90 94:96 ];  %(rclavicle ignored) rhumerus rradius rwrist rhand (fingers are constant) rthumb    

elseif strcmp(MotionData.skel.type,'mit')
  %MIT-style data
  MotionData.indx = [   1:6 7:9 14 19:21 26 31:33 38 43:45 50 55:57 61:63 67:69 ...
    73:75 79:81 85:87 91:93 97:99 103:105 ];
  %Save the offsets, they will be inserted later
  MotionData.offsets = [  MotionData.data{1}(1,10:12); MotionData.data{1}(1,16:18); ...
    MotionData.data{1}(1,22:24); MotionData.data{1}(1,28:30); MotionData.data{1}(1,34:36); ...
    MotionData.data{1}(1,40:42); MotionData.data{1}(1,46:48); MotionData.data{1}(1,52:54); ...
    MotionData.data{1}(1,58:60); MotionData.data{1}(1,64:66); MotionData.data{1}(1,70:72); ...
    MotionData.data{1}(1,76:78); MotionData.data{1}(1,82:84); MotionData.data{1}(1,88:90); ...
    MotionData.data{1}(1,94:96); MotionData.data{1}(1,100:102); MotionData.data{1}(1,106:108)];
elseif strcmp(MotionData.skel.type,'bvh')
  %some dimensions are constant (don't model)
  
  %Original
  %MotionData.BVH_NUM_DIMS = 75;
  %MotionData.BVH_CONST_DIMS = [10:12 16:24 34:39 49:51 61:63 73:75];
  
  %MayRes 2013 - Version 1
%   MotionData.BVH_NUM_DIMS = 114;
%   MotionData.BVH_CONST_DIMS = [8,9,13,15,19,21,26,27,31,33,37,39,43,45,49,51,62,63,67,69,73,75,86,87,91,93,97,99,103,105,109,111, ... % zero
%      7,14,20,25,32,38,44,55,56,57,61,68,74,79,80,81,85,92,98,104,110]; %non-zero
%   
 
 %[7,8,9,13,14,15,19,20,21,25,26,27,31,32,33,37,38,39,43,44,45,49,50,51,55,56,57,61,62,63,67,68,69,73,74,75,79,80,81,85,86,87,91,92,93,97,98,99,103,104,105,109,110,111]
 
  %MayRes 2013 - Version 2
  %MotionData.BVH_NUM_DIMS = 66;
  %MotionData.BVH_CONST_DIMS = [11,12,17,18,23,24,29,30,61,63, ... % zero % non
  %rotated
  %MotionData.BVH_CONST_DIMS = [10,11,16,17,22,23,28,29,61,63, ... % zero
  %    ]; %non-zero
  
  %Dec 2013 - May 2014 
  MotionData.BVH_NUM_DIMS = 84;
  MotionData.BVH_CONST_DIMS = [32,33,37:42,50,51,55:60,64,65,70,71,76,77,82,83, ... % zero
      ]; %non-zero
  
  MotionData.BVH_CONST_DIMS = [31:33,37:39,40:42,49:51,55:57,58:60,64:66,70:72,76:78,82:84];
  
  MotionData.indx = setdiff(1:MotionData.BVH_NUM_DIMS,MotionData.BVH_CONST_DIMS); 
  
  elseif strcmp(MotionData.skel.type,'ms2')
    %Moving Stories: Dec 2013 - May 2014
    BVH_NUM_DIMS = 84;
   
    % this is conversion from non-rotated data
     BVH_CONST_DIMS = [31,32,37:42,59,50,55:60,65,66,71,72,77,78,83,84,
        ]; %non-zero
    
    %BVH_CONST_DIMS = [31:33,37:39,40:42,49:51,55:57,58:60,64:66,70:72,76:78,82:84];
    
    BVH_CONST_DIMS = BVH_CONST_DIMS ; %we have to add extradim to the indices since might add extra column in the invar prep
    MotionData.indx = setdiff(1:BVH_NUM_DIMS,BVH_CONST_DIMS);
elseif strcmp(MotionData.skel.type,'ms2.5')
    %Moving Stories: Dec 2013 - May 2014
    BVH_NUM_DIMS = 84;
    BVH_CONST_DIMS = [32,33,37:42,50,51,55:60,64,65,70,71,76,77,82,83, ... % zero
        ]; %non-zero
    
   % BVH_CONST_DIMS = [31:33,37:39,40:42,49:51,55:57,58:60,64:66,70:72,76:78,82:84];
    
    BVH_CONST_DIMS = BVH_CONST_DIMS; %we have to add extradim to the indices since might add extra column in the invar prep
    MotionData.indx = setdiff(1:BVH_NUM_DIMS,BVH_CONST_DIMS);   
elseif strcmp(MotionData.skel.type,'cmubvh')
  %some dimensions are constant (don't model)
  MotionData.BVH_NUM_DIMS = 96;
  %We don't need to get rid of toes, but we do to make our space smaller
  %This means dimensions 20:21, 35:36 (19,34 are constant anyway)
  %MotionData.BVH_CONST_DIMS = [7:9 13 19:21 22:24 28 34:36 55:57 62 64 66 70:75 76:78 83 85 87 91:96];
  MotionData.BVH_CONST_DIMS = [7:9 13 19:21 22:24 28 34:36 55:57 62 64 66 67:69 70:75 76:78 83 85 87 88:90 91:96];
  MotionData.indx = setdiff(1:MotionData.BVH_NUM_DIMS,MotionData.BVH_CONST_DIMS); 
else
  error('Unknown skeleton type');
end

%combine the data into a large batch
batchdata = cell2mat(MotionData.data'); %flatten it into a standard 2d array
batchdata = batchdata(:,MotionData.indx);
numcases = size(batchdata,1);

%Normalize the data
data_mean = mean(batchdata,1);
data_std = std(batchdata);
batchdata =( batchdata - repmat(data_mean,numcases,1) ) ./ ...
  repmat( data_std, numcases,1);

%Index the valid cases (we don't want to mix sequences)
%This depends on the order of our model
for jj=1:length(MotionData.data)
  seqlengths(jj) = size(MotionData.data{jj},1);
  if jj==1 %first sequence
    batchdataindex = CDBNConfig.LayerOrder(1)+1:seqlengths(jj);
  else
    batchdataindex = [batchdataindex batchdataindex(end)+CDBNConfig.LayerOrder(1)+1: ...
      batchdataindex(end)+seqlengths(jj)];
  end
end

% Here's a convenient place to remove offending frames from the index
% example: offendingframes = [231 350 714 1121];
% batchdataindex = setdiff(batchdataindex,offendingframes);


%now that we know all the valid starting frames, we can randomly permute
%the order, such that we have a balanced training set
permindex = batchdataindex(randperm(length(batchdataindex)));

%should we keep some minibatches as a validation set?
numfullbatches = floor(length(permindex)/MotionData.batchsize);

%fit all minibatches of size MotionData.batchsize
%note that since reshape works in colums, we need to do a transpose here
minibatchindex = reshape(permindex(1: ...
  MotionData.batchsize*(numfullbatches-numvalidatebatches)),...
  MotionData.batchsize,numfullbatches-numvalidatebatches)';
%no need to reshape the validation set into mini-batches
%we treat it as one big batch
validatebatchindex = permindex(...
  MotionData.batchsize*(numfullbatches-numvalidatebatches)+1: ...
  MotionData.batchsize*numfullbatches);  
%Not all minibatches will be the same length ... must use a cell array (the
%last batch is different)
minibatch = num2cell(minibatchindex,2);
%tack on the leftover frames (smaller last batch)
leftover = permindex(MotionData.batchsize*numfullbatches+1:end);
minibatch = [minibatch;num2cell(leftover,2)];


MotionData.mean = data_mean;
MotionData.std = data_std;
MotionData.minibatch = minibatch;
MotionData.batchdata = batchdata;
MotionData.batchdataindex = batchdataindex;
end