function Random_Forest = train_RF(Data,Labels,varargin)
% p = inputParser;
% % addParamValue(p,'all_data','all_pima_indian_data',@ischar);
% %addParamValue(p,'test_data','test_data',@ischar);
% addParamValue(p,'min_parent','100');
% addParamValue(p,'min_leaf','70');
% addParamValue(p,'n_trees','500');
% % addParamValue(p,'actfunc','logistic',@ischar);
% % addParamValue(p,'out','RF_dec9_genetic_LC',@ischar);
% % data_file = (p.Results.all_data);
% min_parent = (p.Results.min_parent);
% min_leaf = (p.Results.min_leaf);
% n_trees = (p.Results.n_trees);
% min_parent = str2double(min_parent);
% min_leaf = str2double(min_leaf);
% n_trees = str2double(n_trees);

% n = (p.Results.emiters);
% actfunc = (p.Results.actfunc);
% hexp = (p.Results.hexp);
%Random_Forest = train_RF(Data,Labels,varargin)
%   
%       Data 	: is nxm matrix, rows are instances and columns are the variables
%
%   Creates an ensemble of CARTrees using Data(samplesXfeatures).
%   The following parameters can be set :
%
%       ntrees        : number of trees in the ensemble (default 50)
%
%       oobe         : out-of-bag error calculation, 
%                      values ('y'/'n' -> yes/no) (default 'n')
%
%       nsamtosample : number of randomly selected (with
%                      replacement) samples to use to grow
%                      each tree (default num_samples)
%
%
%   Furthermore the following parameters can be set regarding the
%   trees themselves :
%
%       method       : the criterion used for splitting the nodes
%                           'g' : gini impurity index (classification)
%                           'c' : information gain (classification)
%                           'r' : squared error (regression)
%
%       minparent    : the minimum amount of samples in an impure node
%                      for it to be considered for splitting
%
%       minleaf      : the minimum amount of samples in a leaf
%
%       weights      : a vector of values which weigh the samples 
%                      when considering a split
%
%       nvartosample : the number of (randomly selected) variables 
%                      to consider at each node 

okargs =   {'minparent' 'minleaf' 'nvartosample' 'ntrees' 'nsamtosample' 'method' 'oobe' 'weights'};
defaults = {100 70 round(sqrt(size(Data,2))) 300 numel(Labels) 'r' 'n' []};
[eid,emsg,minparent,minleaf,m,nTrees,n,method,oobe,W] = getargs(okargs,defaults,varargin{:});

avg_accuracy = 0;
for i = 1 : nTrees
     
    TDindx = round(numel(Labels)*rand(n,1)+.5);
%    TDindx = unique(TDindx);
%     TDindx = randsample(numel(Labels),n,true);
%     TDindx = unique(TDindx);
    
    Random_ForestT = cartree(Data(TDindx,:),Labels(TDindx), ...
        'minparent',minparent,'minleaf',minleaf,'method',method,'nvartosample',m,'weights',W);
    
    Random_ForestT.method = method;

    Random_ForestT.oobe = 1;
    if strcmpi(oobe,'y')        
        NTD = setdiff(1:numel(Labels),TDindx);
        tree_output = eval_cartree(Data(NTD,:),Random_ForestT)';
        
        switch lower(method)        
            case {'c','g'}                
                Random_ForestT.oobe = numel(find(tree_output-Labels(NTD)'==0))/numel(NTD);
            case 'r'
                Random_ForestT.oobe = sum((tree_output-Label(NTD)').^2);
        end        
    end
    
    Random_Forest(i) = Random_ForestT;

    accuracy = Random_ForestT.oobe;
    if i == 1
        avg_accuracy = accuracy;
    else
        avg_accuracy = (avg_accuracy*(i-1)+accuracy)/i;
    end

    display(['--->Tree#',num2str(i),' created: Accu. = ', num2str(Random_ForestT.oobe)]);
    display(['/// Overall Accuracy = ', num2str(avg_accuracy)]);
end
