function [kl_bits, a_plot] = calcKLmodel(a_hist_db, dist_model, props)

% calcKLmodel - Calculates the Kullback-Leibler divergence of the histogram to a model distribution.
%
% Usage:
% [mode_val, mode_mag] = calcKLmodel(a_hist_db)
%
% Parameters:
%   a_hist_db: A histogram_db object.
%   dist_model: Structure that contains the distribution parameters. Must
%   	be one of these:
%	Normal distribution: struct('dist', 'norm', 'mu', mean, 'sigma', var)
%	Poisson distribution: struct('dist', 'pois', 'lambda', l)
%	Exponential distribution: struct('dist', 'exp', 'mu', m)
%	Uniform distribution: struct('dist', 'uni')
%   props: Structure with optional parameters.
%     plot: If 1, return a plot_abstract object with both distributions.
%		
% Returns:
%   kl_bits: The calculated divergence in bits.
%
% Description:
%
% See also: histogram_db
%
% $Id$
%
% Author: Cengiz Gunay <cgunay@emory.edu>, 2009/03/24

% Copyright (c) 2007 Cengiz Gunay <cengique@users.sf.net>.
% This work is licensed under the Academic Free License ("AFL")
% v. 3.0. To view a copy of this license, please look at the COPYING
% file distributed with this software or visit
% http://opensource.org/licenses/afl-3.0.php.

if ~ exist('props', 'var')
  props = struct;
end

data = get(a_hist_db, 'data');

% approximate bin size from first two bin centers
bin_size = diff(data(1:2, 1));

% Normalize histogram to simulate a probability distribution function
% (PDF)
norm_data = data(:, 2) / sum(data(:, 2));

% Find ranges
%data_range = [ min(data(:, 1)) max(data(:, 1))];

% Calculate theoretical distribution

% TODO: put these in common place in private directory to plot on top of
% histogram
switch dist_model.dist
  case 'norm'
    prob_func = ...
        @(x)(1./(dist_model.sigma * sqrt(2 * pi)) * ...
             exp( - (x-dist_model.mu).^2./(2*dist_model.sigma^2)));
  case 'pois'
  case 'exp'
  case 'uni'
  otherwise
    error([ 'Probability distribution "' dist_model.dist ' not recognized.']);
end

% multiply by bin size to get average prob for the whole bin
% (integration would've been more accurate)
dist_data = prob_func(data(:, 1)) * bin_size;

% Calculate KL divergence
kl_bits = calcKL(norm_data, dist_data);

if isfield(props, 'plot')
  a_hist_db.tests_db.data = [ data(:, 1), norm_data ];
  a_plot = ...
      plot_superpose({...
        plot_abstract(a_hist_db, ...
                      ['Compare to ' dist_model.dist ...
                      ' distribution'], ...
                      mergeStructs(props, struct('shading', ...
                                                 'flat'))), ...
                     plot_abstract({data(:, 1), dist_data}, ...
                                   {}, '', { [ dist_model.dist ' dist.'] }, ...
                                   'plot', props)});
end
  