function obj = update_feature_with_matchdata( obj,database,varargin )
% feature extraction based on database
inspdata = GLOBALCONST.GET_VAR(GLOBALCONST.VARNAME_INSPECTDATA);

pp = inputParser;
pp.addParamValue('votedensity',1.0,@(x)x<=1 && x>0);
pp.addParamValue('useclustercp',true); %cluster candpivot to save computation?
pp.addParamValue('usecontext',true); %use context score?
pp.addParamValue('usesimplecluster',false); %use simple clustering in per-label clustering?
pp.parse(varargin{:});
% extract match scoremap and vote points
use_simple_clustering = pp.Results.usesimplecluster;
% input('warning: use simple clustering?','s');

if isempty(obj.m_matchdatalist)
    warning('no match data, perform matching first');
    obj = obj.match_to_database(database);
end
matchdatalist = obj.m_matchdatalist;
% input('warning: not removing unreliable matches?','s');
matchdatalist = srec_remove_unreliable_matches(matchdatalist);

nobj = length(matchdatalist);
dblbs = obj.m_dblbs;
sketchimg = obj.m_sketchimg;

[is js] = find(obj.m_sketchimg);
cxpts = [is(:) js(:)]';
obj.m_cxpts = cxpts;

%collect candidate pivots
candpivots = {};
lbs_per_candpivot = {};
candpivot2cxpts = {};
matchscores = {};
segid_per_candpivot = {};
dftransmat_per_candpivot = {};
fprintf(1,'SKETCH:collecting candpivots\n');
for i=1:nobj
    md = matchdatalist{i};
    nseg = length(md.m_labels);
    
    candpos_per_seg = md.m_candposlist;
    coverage_per_seg = md.m_coverage_per_candpos_list;
    for k=1:nseg
        cpts = candpos_per_seg{k};
        lbs = repmat(md.m_labels(k),1,size(cpts,2));
%         scoremap = md.m_smaplist_by_fit{k};
%         idx = sub2ind(size(scoremap),cpts(1,:),cpts(2,:));
%         scores = scoremap(idx);
        coverage = coverage_per_seg{k};
%         scores = (scores(:).*coverage(:))';
        scores = coverage(:)';
        cp2cxpts = md.m_candpos2sketchpts_list{k}>0;
        
        candpivots{end+1} = cpts;
        lbs_per_candpivot{end+1} = lbs;
        candpivot2cxpts{end+1} = cp2cxpts;
        matchscores{end+1} = scores(:)';
        dftransmat_per_candpivot{end+1} = md.m_dftransmatlist_per_seg{k};
        
        segids = repmat(md.m_segids(:,k),1,size(cpts,2));
        segid_per_candpivot{end+1} = segids;
    end
end

% merge the lists
candpivots =cat(2,candpivots{:});
lbs_per_candpivot = cat(2,lbs_per_candpivot{:});
candpivot2cxpts = cat(1,candpivot2cxpts{:});
matchscores = cat(2,matchscores{:});
segid_per_candpivot = cat(2,segid_per_candpivot{:});
dftransmat_per_candpivot = cat(2,dftransmat_per_candpivot{:});

% cluster pivots for each label
nlabel = length(dblbs);
tmplist = cell(6,nlabel);%candpivot,lbs,cp2cxpts,scores,segid,dftransmat
for i=1:length(dblbs)
    thislb = dblbs(i);
    
    idx = find(lbs_per_candpivot==thislb);
    thiscps = candpivots(:,idx);
    thiscores = matchscores(idx);
    thiscp2cxpts = candpivot2cxpts(idx,:);
    thisegids = segid_per_candpivot(:,idx);
    thisdftransmatlist = dftransmat_per_candpivot(idx);
    
    lbname = util_get_name_by_label(thislb);
    lbname = lbname{1};
    
    fprintf(1,'SKETCH clustering: processing %d %s\n',length(idx), lbname);
%     fprintf(1,'SKETCH clustering: computing justenough coverage\n');
%     thiscp2cxpts_justenough = srec_cover_justenough(thisegids,...
%         thisdftransmatlist,obj,database);
    thiscp2cxpts_justenough = thiscp2cxpts;
    
    fprintf(1,'SKETCH clustering: running...\n');
    if pp.Results.useclustercp
        if use_simple_clustering
            [clbs,idxcts] = SBSRSKETCH.cluster_candpivots(thiscps,thiscores,thiscp2cxpts_justenough,...
                'distfunc',@srec_distfunc_norm2,'usescoredist',false,...
                'usecenterdist',false,'useiter',true);
        else
            topn = 3;
            clbs = srec_cluster_compts_by_farthest_sampling_raw(thiscp2cxpts_justenough,0.4);
            idxcts = pick_compts_per_cluster_by_bestmatch(clbs,thiscores,topn);
        end
        
        if ~isempty(idxcts)
            inspdata.m_match_before_lbcluster_candpivot = thiscps;
            inspdata.m_match_before_lbcluster_clbs = clbs;
            inspdata.m_match_after_lbcluster_candpivot = thiscps(:,idxcts);
            inspdata.m_match_after_lbcluster_scores = thiscores(idxcts);
        end
    else
        idxcts = 1:size(thiscps,2);
    end
%     idxcts = 1:size(thiscps,2);
    tmplist{1,i} = thiscps(:,idxcts);
    tmplist{2,i} = repmat(thislb,1,length(idxcts));
    tmplist{3,i} = thiscp2cxpts(idxcts,:);
    tmplist{4,i} = thiscores(idxcts);
    tmplist{5,i} = thisegids(:,idxcts);
    tmplist{6,i} = thisdftransmatlist(idxcts);
end

candpivots = cat(2,tmplist{1,:});
lbs_per_candpivot = cat(2,tmplist{2,:});
candpivot2cxpts = cat(1,tmplist{3,:});
matchscores = cat(2,tmplist{4,:});
segid_per_candpivot = cat(2,tmplist{5,:});
dftransmat_per_candpivot = cat(2,tmplist{6,:});

obj.m_candpivots = candpivots;
obj.m_lbs_per_candpivot = lbs_per_candpivot;
obj.m_candpivot2cxpts = candpivot2cxpts>0;
obj.m_matchscore_per_candpivot = matchscores;
obj.m_segid_per_candpivot = segid_per_candpivot;
obj.m_dftransmat_per_candpivot = dftransmat_per_candpivot;

obj.m_symask_candpivot2candpivot = false(size(candpivots,2));
obj = obj.update_feature_with_candpivot(database);

if pp.Results.useclustercp && ~use_simple_clustering
    % evaluate context match and cluster the candpivots again
    obj = obj.match_to_database_by_context(database);
    score_per_candpivot = obj.get_candpivot_scores;
    dblbs = database.m_labels;
    maskcpsuse = false(1,size(obj.m_candpivots,2));
    for i=1:length(dblbs)
        idxcps_thislb = find(obj.m_lbs_per_candpivot == dblbs(i));
        
        fprintf(1,'SKETCH clustering 2nd: label=%d, n=%d\n',dblbs(i),length(idxcps_thislb));
        thiscps = obj.m_candpivots(:,idxcps_thislb);
        thiscores = score_per_candpivot(idxcps_thislb);
        thiscp2cxpts = obj.m_candpivot2cxpts(idxcps_thislb,:);
        [~,idxcts] = SBSRSKETCH.cluster_candpivots(thiscps,thiscores,thiscp2cxpts,...
            'distfunc',@srec_distfunc_overlap_by_sample,'usescoredist',true,'useiter',true);
        idxcps_use = idxcps_thislb(idxcts);
        maskcpsuse(idxcps_use) = true;
    end
    idxremove =find(~maskcpsuse);
    obj = obj.remove_candpivot(idxremove);
    obj = obj.update_feature_with_candpivot(database);
end

obj = obj.match_to_database_by_context(database);

GLOBALCONST.SET_VAR(GLOBALCONST.VARNAME_INSPECTDATA,inspdata);

end

function idxcompts = pick_compts_per_cluster_by_bestmatch(clbs,scores,topn)
% pick topn matching components from clusters

uclbs = unique(clbs);
idxcompts = cell(1,length(uclbs));
for i=1:length(uclbs)
    idxinclust = find(clbs == uclbs(i));
    scores_inclust = scores(idxinclust);
    idxuse = util_topn(scores_inclust,topn);
    idxuse = idxinclust(idxuse);
    idxcompts{i} = idxuse(:)';
end

idxcompts = cat(2,idxcompts{:});
end

function obj = update_feature_with_matchdata_old( obj,varargin )
% feature extraction based on database

pp = inputParser;
pp.addParamValue('votedensity',1.0,@(x)x<=1 && x>0);
pp.parse(varargin{:});
nvote_per_seg = ceil(pp.Results.votedensity * 10);

% extract match scoremap and vote points

if isempty(obj.m_matchdatalist)
    warning('no match data, perform matching first');
    obj = obj.match_to_database(database);
end
matchdatalist = obj.m_matchdatalist;

% update vote points
for i=1:length(matchdatalist)
    matchdatalist{i} = srec_votepts_from_matchdata(obj,matchdatalist{i},nvote_per_seg);
end
obj.m_matchdatalist = matchdatalist;

% these are not per-obj list, they are concatenation of per-obj list
voteptslist = {};
xymatlist = {};
scoremaplist = {};
lbs = [];

for i=1:length(matchdatalist)
    matchdata = matchdatalist{i};
    voteptslist = cat(2,voteptslist,matchdata.m_voteptslist);
    
    % use maxfilt scoremap
    scoremaplist = cat(2,scoremaplist,matchdata.m_smaplist_by_maxfilt);
    
    xymat_per_seg = cell(1,length(matchdata.m_labels));
    for k=1:length(matchdata.m_idxmatlist_by_maxfilt)
        sz = size(matchdata.m_smaplist_by_maxfilt{k});
        idx = matchdata.m_idxmatlist_by_maxfilt{k};
        [xs ys] = ind2sub(sz,idx);
        xymat_per_seg{k} = cat(3,xs,ys);
    end
    xymatlist = cat(2,xymatlist,xymat_per_seg);
    
    lbs = cat(2,lbs,matchdata.m_labels(:)');
end

% 
[votepts_per_ulb,ulbs] = srec_merge_votepts(voteptslist,lbs);

% merge score map
scoremap_per_ulb = cell(1,length(ulbs));
xymat_per_ulb = cell(1,length(ulbs));
for i=1:length(ulbs)
    thislb = ulbs(i);
    mask = lbs == thislb;
    smaplist = scoremaplist(mask);
    scorecube = cat(3,smaplist{:});
    
    xcube = cellfun(@(x)x(:,:,1),xymatlist(mask),'uniformoutput',false);
    xcube = cat(3,xcube{:});
    ycube = cellfun(@(x)x(:,:,2),xymatlist(mask),'uniformoutput',false);
    ycube = cat(3,ycube{:});
    
    [maxscoremap,idxmax] = max(scorecube,[],3);
    
    % get coordinates for each maximum point
    [ii jj] = ndgrid(1:size(scorecube,1),1:size(scorecube,2));
    idx = sub2ind(size(scorecube),ii,jj,idxmax);
    xs = xcube(idx);
    ys = ycube(idx);
    xymat = cat(3,xs,ys);
    
    scoremap_per_ulb{i} = maxscoremap;
    xymat_per_ulb{i} = xymat;
end

% extract sample points
obj.m_match_scoremaps = scoremap_per_ulb;
obj.m_xymat_per_match_scoremap = xymat_per_ulb;
obj.m_label_per_match_scoremap = ulbs;

sketchimg = obj.m_sketchimg;
gridsize = [30 30];
vpts = cat(2,votepts_per_ulb{:});

% per label per point scoremap and xymat, xymat(label,idxpts,:) = a point
[lbpts_scoremap,lbpts_xymat] = obj.get_matchinfo_by_pts(ulbs,vpts);

% per point scores 
[scores,idxmax] = max(lbpts_scoremap,[],1);
xmat = lbpts_xymat(:,:,1);
ymat = lbpts_xymat(:,:,2);
idx = sub2ind(size(lbpts_scoremap),idxmax,1:length(idxmax));
xs = xmat(idx);
ys = ymat(idx);
cpts_per_sample = [xs(:) ys(:)]';
lbs_per_sample = ulbs(idxmax);

% select subset of vote points
[samplepts,idxsample] = SBSRSKETCH.select_sample_by_votepts_in_grid(...
    sketchimg,gridsize,vpts,scores);
cpts_per_sample = cpts_per_sample(:,idxsample);
lbs_per_sample = lbs_per_sample(idxsample);

% extract line direction context
% cxcubes_ldir = srec_context_line_direction(sketchimg,samplepts);
cxcubes_ldir = srec_context_line_direction(sketchimg,cpts_per_sample);

% extract label context
scx_ndist = GLOBALCONST.SCX_NDIST;
scx_ndir = GLOBALCONST.SCX_NDIR;
maxdist = norm(GLOBALCONST.DEFAULT_SKETCH_SIZE) * GLOBALCONST.SCX_MAXDIST_TO_DIAG;
dblbs = obj.m_dblbs;

% prepare vote point data: component center and weight
scxdatalist = cell(1,length(ulbs));%data(1:2,:)=cpts,data(3,:)=score,data(4,:)=labels
for i=1:length(votepts_per_ulb)
    thisvpts = votepts_per_ulb{i};
    thiscoremap = scoremap_per_ulb{i};
    thislb = ulbs(i);
    
    idx = sub2ind(size(thiscoremap),thisvpts(1,:),thisvpts(2,:));
    scores = thiscoremap(idx);
    
    % normalize score for each label so that the scx count is not related
    % to number of vpts
    totalscore = sum(scores);
    if totalscore ~= 0
        scores = scores/totalscore;
    else
        scores(:)=1;
    end
    
    xymat = xymat_per_ulb{i};
    xmat = xymat(:,:,1);
    ymat = xymat(:,:,2);
    xs = xmat(idx);
    ys = ymat(idx);
    thiscpts = [xs(:) ys(:)]';
    
    thisdata = zeros(4,size(thisvpts,2));
    thisdata(1:2,:)=thiscpts;
    thisdata(3,:)=scores;
    thisdata(4,:)=thislb;
    scxdatalist{i} = thisdata;
end
scxdata = cat(2,scxdatalist{:});
datapts = scxdata(1:2,:);
dataws = scxdata(3,:);
datalbs = scxdata(4,:);

% label context for each sample 
cxcubes_label = srec_context_label_from_pts(datapts,datalbs,dblbs,maxdist,...
    'pivotpts',cpts_per_sample,'weight',dataws);

obj.m_cxcubes_label = cxcubes_label;
obj.m_cxcubes_ldir = cxcubes_ldir;
obj.m_cxpts = samplepts;

obj = obj.update_fullcover(database);
GLOBALCONST.SET_VAR(GLOBALCONST.VARNAME_INSPECTDATA,inspdata);

end

