function adaboostLearn(category,posTrainImagePaths,negTrainImagePaths,numWeakClassifiers,templateSize,scale)
% LearnAdaboostTemplate - Learns an adaboost "template", i.e. strong classifier. 
%
% category: the category of training images
% imagepaths: path of training images
% scale: scale of Gabors

tic
addpath('../common');
% negTrainImagePaths = negTrainImagePaths(1:50); !!! remember to remove this
negTrainImagePaths = negTrainImagePaths(1:400);

if nargin < 4
    numWeakClassifiers = 30;
end

if nargin < 5
    templateSize = [120 120];
end

if nargin < 6
    scale = .7;
end

numGridPoint = 50;
subsampleStep = 2; % sub sample rate that weak classifiers go over
norient = 16;  % number of orientations
[allfilter allsymbol] = makefilter(scale, norient);  % generate Gabor filters 
h = (size(allfilter{1}, 1)-1)/2;  % half size of Gabor
Lrange = 6; % allowed shifting in location (times subsampleStep pixels)
Orange = 1; % allowed shifting in orientation


posMaps = getGaborMaps(posTrainImagePaths,templateSize,allfilter); % compute Sum1 maps
%     Cmax(nimage, norient, posMaps, templateSize(1), templateSize(2), Lrange, Orange, subsampleStep); % compute Max1 maps
n = length(posTrainImagePaths);
M1TraceMap = cell(n,norient);
subsampleM1 = 1;
for i = 1:n
    [posMaps(i,:) M1TraceMap(i,:) rowShifts colShifts oriShifts] = ...
        CcomputeMAX1(norient,posMaps(i,:),double(Lrange)/(2*h+1),Orange,h*2+1,subsampleM1);
end

negMaps = getGaborMaps(negTrainImagePaths,templateSize,allfilter); % compute Sum1 maps
n = length(negTrainImagePaths);
for i = 1:n
    negMaps(i,:) = CcomputeMAX1(norient,negMaps(i,:),double(Lrange)/(2*h+1),Orange,h*2+1,subsampleM1);
end

% initial data weights: balanced
dataWeights = 0.5 * [ ones(1, length(posTrainImagePaths)) / length(posTrainImagePaths), ...
    ones(1,length(negTrainImagePaths)) / length(negTrainImagePaths) ];

disp(sprintf('mex-C adaboost learning ----------- #pos: %d, #neg: %d',length(posTrainImagePaths),length(negTrainImagePaths)));
[selectedXs selectedYs selectedOs selectedThresholds selectedPolars lambdas]...
    = adaboostLearning(posMaps,negMaps,...
    dataWeights,numGridPoint,h,subsampleStep,numWeakClassifiers);

scoresPos = adaboostTesting(posMaps,selectedXs,selectedYs,selectedOs,selectedThresholds,selectedPolars,lambdas);
scoresNeg = adaboostTesting(negMaps,selectedXs,selectedYs,selectedOs,selectedThresholds,selectedPolars,lambdas);

disp(['training time: ' num2str(toc) ' seconds']);
clear posTrainImages
clear negTrainImages
clear negMaps

% obtain the symbolic template and deformed symbolic templates
n = length(posTrainImagePaths);
symbolicTemplate = displaySelectedFilters(allsymbol,lambdas,selectedPolars,selectedXs,selectedYs,selectedOs,templateSize);
deformedTemplate = cell(n,1);
for i = 1:n
    xlist = zeros(numWeakClassifiers,1);
    ylist = zeros(numWeakClassifiers,1);
    olist = zeros(numWeakClassifiers,1);
    on_off_vec = zeros(numWeakClassifiers,1);
    for j = 1:numWeakClassifiers
        x = selectedXs(j);
        y = selectedYs(j);
        o = selectedOs(j);
        shiftInd = M1TraceMap{i,o+1}(x+1,y+1)+1;
        if shiftInd <= 0 || shiftInd > length(rowShifts{1})
            disp(shiftInd);
        end
        xlist(j) = x + rowShifts{1}(shiftInd);
        ylist(j) = y + colShifts{1}(shiftInd);
        olist(j) = o + oriShifts{1}(shiftInd);
        while olist(j) < 0
            olist(j) = olist(j) + norient; 
        end
        while olist(j) >= norient
            olist(j) = olist(j) - norient; 
        end
        on_off_vec(j) = selectedPolars(j) == (posMaps{i,olist(j)+1}(xlist(j)+1,ylist(j)+1) > selectedThresholds(j));
    end
    
    deformedTemplate{i} = displaySelectedFilters(allsymbol,lambdas(:) .* double(on_off_vec(:)),selectedPolars,xlist,ylist,olist,templateSize);
end

clear posMaps
rootFolder = '..';
mkdir(sprintf('%s/result/%s',rootFolder,category));
save(sprintf('%s/result/%s/adaboost_model.mat',rootFolder,category),...
    'selectedXs','selectedYs','selectedOs','selectedThresholds',...
    'selectedPolars','lambdas','scoresPos','scoresNeg','numGridPoint',...
    'templateSize','symbolicTemplate','deformedTemplate');



