function [strings, err, pp, resid] = bfitcalcfit(datahandle,fit)
% BFITCALCFIT  Calculate coefficients and residuals of FIT to data DATAHANDLE.

%   Copyright 1984-2004 The MathWorks, Inc.
%   $Revision: 1.21.4.6 $  $Date: 2004/11/29 23:31:18 $

strings = ' ';
err = 0;

if fit < 0 % select fit is cleared
    setappdata(double(datahandle),'Basic_Fit_NumResults_',[]);
    return
end

% get data
guistate = getappdata(double(datahandle),'Basic_Fit_Gui_State');
xdata = get(datahandle,'xdata');
ydata = get(datahandle,'ydata');

% calculate fit with warnings turned off
ws = warning('off', 'all'); 
[lastwarnmsg, lastid] = lastwarn; % save warning in case no new warning
lastwarn('')
try
    [pp, resid, err, warnmsg] = calcfit(xdata,ydata,fit,datahandle,guistate);
catch
    err = 1;
    warnmsg = '';
end
lastwarn(lastwarnmsg, lastid); % set lastwarn to last warning
warning(ws);

% quit if error, warn if warning
if err
    return;
end
if isempty(warnmsg)
    dlgh = [];
else
    dlgh = warndlg(warnmsg,'Basic Fitting');
end
setappdata(double(datahandle),'Basic_Fit_Dialogbox_Handle',dlgh);


value = getappdata(double(datahandle),'Basic_Fit_Coeff');
% we assume this is initialized in setup as cell array
value{fit + 1} = pp;
setappdata(double(datahandle),'Basic_Fit_Coeff', value);

value = getappdata(double(datahandle),'Basic_Fit_Resids');
% we assume this is initialized in setup as a cell array
value{fit + 1} = resid;
setappdata(double(datahandle),'Basic_Fit_Resids', value);

% save last fit calculated
setappdata(double(datahandle),'Basic_Fit_NumResults_',fit);

% get other needed strings
strings = bfitcreateeqnstrings(fit,pp,norm(resid));

% ----------------------------------------------
function [pp,resid,err,warnmsg] = calcfit(xdata,ydata,fit,datahandle,guistate)
% CALCFIT calculates a fit.
%    [COEFF, RESID, ERR, WMSG] = CALCFIT(X,Y,FIT) calculates a fit and 
%    returns coefficients in a form PPVAL or POLYVAL can understand, 
%    the residuals, an error indicator, and warning messages.

err = 0;
warnmsg = '';
distincterrid = 'MATLAB:chckxy:RepeatedSites';
twodataerrid = 'MATLAB:chckxy:NotEnoughPts';
title = 'Basic Fitting';

% Remove NaN values but remember doing so
nanmask = isnan(xdata(:)) | isnan(ydata(:));
nandata = any(nanmask);
if nandata
   xdata(nanmask) = [];
   ydata(nanmask) = [];
end

if fit == 0 % spline
    if guistate.normalize
	    normalized = getappdata(double(datahandle),'Basic_Fit_Normalizers');
        newxdata  = (xdata - normalized(1))./(normalized(2));
    else
	    newxdata = xdata;
    end
    try
        pp = spline(newxdata,ydata);
    catch
        pp = [];
        resid = [];
        err = 1;
        [ignore, lastid] = lasterr;
        if strcmp(lastid,distincterrid)
            errmsg = sprintf(['Repeated X values are not permitted when fitting\n' ...
                    'with a cubic interpolating spline.\n' ...
                    'Remove repeated values.']); 
            dlgh = bfitcascadeerr(errmsg,title);
        elseif strcmp(lastid,twodataerrid)
            errmsg = sprintf(['At least two data points are required when\n' ...
                    'fitting with a cubic interpolating spline.\n' ...
                    'Add more data points to fit with spline.']);
            dlgh = bfitcascadeerr(errmsg,title);
        else
            dlgh = bfitcascadeerr({lasterr},title);
        end
        setappdata(double(datahandle),'Basic_Fit_Dialogbox_Handle',dlgh);
        return;
    end
    y = ppval(pp,newxdata);     % this should be all zeros for spline
elseif fit == 1 % pchip
    if guistate.normalize
    	normalized = getappdata(double(datahandle),'Basic_Fit_Normalizers');
        newxdata  = (xdata - normalized(1))./(normalized(2));
    else
		newxdata = xdata;
    end
    try
		pp = pchip(newxdata,ydata);
    catch
        pp = [];
        resid = [];
        err = 1;
        [ignore, lastid] = lasterr;
        if strcmp(lastid,distincterrid)
            errmsg = sprintf(['Repeated X values are not permitted when fitting\n' ...
                    'with shape-preserving interpolants.\n' ...
                    'Remove repeated values.']);
            dlgh = bfitcascadeerr(errmsg,title);
        elseif strcmp(lastid,twodataerrid)
            errmsg = sprintf(['At least two data points are required when\n' ...
                    'fitting with shape-preserving interpolants.\n' ...
                    'Add more data points.']);
            dlgh = bfitcascadeerr(errmsg,title);
        else
            dlgh = bfitcascadeerr({lasterr},title);
        end
        setappdata(double(datahandle),'Basic_Fit_Dialogbox_Handle',dlgh);
        return;
    end
    y = ppval(pp,newxdata);     % this should be all zeros for pchip
else % polynomial
    order = fit-1;
    centerscalestr = sprintf( ...
            ['Polynomial is badly conditioned. Remove repeated data points\n' ...
                '         or try centering and scaling as described in HELP POLYFIT.']);
    repeatptsstr = ...
      sprintf('Polynomial is badly conditioned. Remove repeated data points');
    if guistate.normalize
		% polyfit calculates normalizers, so we don't have to getappdata.
        [pp,ignore,normalizers] = polyfit(xdata,ydata,order);
    else
        pp = polyfit(xdata,ydata,order);
    end
    if ~isempty(lastwarn)
        centerwarn = ~isempty(findstr(centerscalestr,lastwarn));
        repeatwarn = ~isempty(findstr(repeatptsstr,lastwarn));
        if centerwarn || repeatwarn
            waswarned = getappdata(double(datahandle),'Basic_Fit_Scaling_Warn');
            if isempty(waswarned)
                % only give these warnings once per data set
                setappdata(double(datahandle),'Basic_Fit_Scaling_Warn',1);
                if centerwarn
                    warnmsg = sprintf( ...
                    ['Polynomial is badly conditioned. Removing repeated data points, \n' ...
                        'or centering and scaling, may improve results.']);
                else
                    warnmsg = sprintf( ...
                    ['Polynomial is badly conditioned. \nRemoving repeated data points ' ...
                        'may improve results.']);
                end
            end
            lastwarn('');
        end
    end
	if guistate.normalize
	    y = polyval(pp,xdata,[],normalizers);
	else
	    y = polyval(pp,xdata);
	end
end

resid = ydata(:) - y(:);  % always column
if nandata
   fullresid = repmat(NaN,size(nanmask));
   fullresid(~nanmask) = resid;
   resid = fullresid;
end

% Capture warning messages not handled earlier
if isempty(warnmsg)
    warnmsg = lastwarn;
end

% expand warning message if any nan data
if nandata && isempty(getappdata(double(datahandle),'Basic_Fit_NaN_Warn'))
    % only give these warnings once per data set
    setappdata(double(datahandle),'Basic_Fit_NaN_Warn',1);
    nanerrstr = 'Some data points have NaN coordinates.  These will be ignored in the fit.';
    if isempty(warnmsg)
        warnmsg = nanerrstr;
    else
        warnmsg = sprintf('%s\n\n%s',warnmsg,nanerrstr);
    end
end

