function Classifier_MultiClass_Directed( cFcn, cPoints, cTrainlabels, cExtraParam)

%
% IN:
%   gClassifierObj  : global struct containing the state of the object.
%                     Struct containing at least:
%                     L : current labels for the points
%                     Stop : boolean flag, set to true when the classifier is happy with the classification
%   gDiffuseObj     : see Diffuser_Template. 
%   cFcn : string specifying the action to be taken. Should support at least:
%          'create'     : creates and initializes gClassifierObj
%          'classify'   : classifies the points according to the given parameters
%   cExtraParam     : when cFcn=='create', this structure should contain
%                           Diffuser    : a diffuser according to Diffuser_Template. On top of that Diffuser should be able the following action(s):
%                                         'plug' : accepts a list of indices of heated points from which there should be no diffusion any more
%                           Type        : type of classifier ('standard' means MAP estimate; 'consistent' means implementation of Szummer-Jaakola algorithm [NIPS'01'])  
% OUT:
%   gClassifierObj  : updated global struct with the state of classifier. Contains:
%                     L : current labels for the points
%                     Stop : boolean flag, set to true when the classifier is happy with the classification
%                     score_per_pt: margin/score for each labeled point; M-by-1 vector
%                     % (removed) class_score: margin/score of each class averaged over all pts in that class; NumClasses-by-1 vector
%                     % (removed) av_score: weighted average score (averaged over all points that   
%
%   gDiffuseObj     : possibly updated gDiffuseObj
%
%
% SOURCE CONTROL
%   Ann Lee, 3/10/04
%   Last modified,  AL 3/18/04 [added normalization of class posteriors and added a variable gClassifierObj.class_score for each class]
%                   AL 3/26/04 [added gClassifierObj.score_per_pt and gClassifierObj.avscore]
%                   AL 6/22/04 [added gClassifierObj.ClassPost --- normalized class posterior]

global gClassifierObj;
global gDiffuseObj;

if strcmpi(cFcn,'create')==1
    gClassifierObj = [];
    gClassifierObj.Stop = false;
    %gClassifierObj.Heat = gDiffuseObj.Heat;
    [dummy,tmpL]=max(abs(gDiffuseObj.Heat),[],1); tmpidx=find(dummy>eps);   
    gClassifierObj.L = zeros(gDiffuseObj.M,1); gClassifierObj.L(tmpidx)=tmpL(tmpidx);
    gClassifierObj.ClassPost = zeros(size(gDiffuseObj.Heat));  % new 
    gClassifierObj.ClassPost(gClassifierObj.L(tmpidx),tmpidx)=1;  % new
    %gClassifierObj.class_score = zeros(gDiffuseObj.NumClasses,1);
    gClassifierObj.score_per_pt = zeros(gDiffuseObj.M,1); 
    % gClassifierObj.avscore=0;
elseif strcmpi(cFcn,'classify')==1
    switch cExtraParam.Type
        case 'standard'   % MAP estimate
            %tmpHeat=full(gDiffuseObj.Heat);  tmpidx=find(gDiffuseObj.AFlags==1); tmpHeat=tmpHeat(:,tmpidx);
            %[dummy,tmplabels] = max(tmpHeat,[],1); gClassifierObj.L(tmpidx)=tmplabels;
            %[tmpidx,tmplabels']
            %lClassPost=zeros(gDiffuseObj.NumClasses,gDiffuseObj.M); 
            tmpsum=sum(gDiffuseObj.Heat,1); tmpidx=find((gDiffuseObj.AFlags==1) &(tmpsum'>eps)); 
            tmpHeat=full(gDiffuseObj.Heat); tmpHeat=tmpHeat(:,tmpidx); 
            %lClassPost=(tmpHeat(:,tmpidx))./(ones(gDiffuseObj.NumClasses,1)*tmpsum(tmpidx));  % Added, AL 3/18/04
            lClassPost=tmpHeat./(ones(gDiffuseObj.NumClasses,1)*sum(tmpHeat,1));% NumClasses-by-Ntmp
            [dummy, tmpL] = max(lClassPost,[],1); 
            gClassifierObj.L(tmpidx)=tmpL;
            gClassifierObj.ClassPost(:,tmpidx)=lClassPost; % NumClasses-by-Ntmp
            
            % Calculate scores:
            tmp = sort(lClassPost,1); % sort class posteriors in ascending order
            tmp_class=ones(gDiffuseObj.NumClasses-1,1)*tmp(gDiffuseObj.NumClasses,:);  % (NumClasses-1)-by-Ntmp
            tmp_rest=tmp(1:gDiffuseObj.NumClasses-1,:); % (NumClasses-1)-by-Ntmp
            tmp_score = mean(tmp_class-tmp_rest,1);   % score, 1-by-Ntmp
            gClassifierObj.score_per_pt(tmpidx) = tmp_score;  % update score per point; Added AL 3/26/04
            %gClassifierObj.avscore = mean(tmp_score); %mean(tmp_score);
            %for lClass=1:gDiffuseObj.NumClasses
            %    tmpidx2=find(tmpL==lClass); %Nc=length(tmpidx2);
            %    if ~isempty(tmpidx2), 
            %        gClassifierObj.class_score(lClass)=mean(tmp_score(tmpidx2)); %mean(tmp_score(tmpidx2)); % update average score per class
            %    end,
            %end
            
        case 'consistent'  % NIPS'01 algorithm
            % fill in later?
        otherwise
            disp('Not a classifier option');
    end 
end;

return;