function c = accumulatefi(a,b,mode,varargin)
%#codegen

%   Copyright 2011-2014 The MathWorks, Inc.

coder.internal.prefer_const(mode);
coder.internal.prefer_const(varargin);

% The mode is a constant and is either 'pos' or 'neg' for accumpos (a+b) or accumneg (a-b)
eml_invariant(eml_is_const(mode),'fixed:coder:mustBeConstant','mode input');

switch nargin
  case 3 % only a & b are provided, roundmode & overflowmode default to 'floor & 'wrap'
    roundmode = 'floor';
    overflowmode = 'wrap';
  case {4,5} % a, b, roundmode provided. overflowmode may be provided (default: 'wrap')
    eml_invariant(eml_is_const(varargin{1}),'fixed:coder:mustBeConstant','rounding method');
    roundmode = varargin{1};
    if (nargin < 5)
        overflowmode = 'wrap';
    else
        eml_invariant(eml_is_const(varargin{2}),...
                      'fixed:coder:mustBeConstant','overflow action');
        overflowmode = varargin{2};
    end
end

% a and/or b must be a fi. Otherwise we would not be in this function.
% Get the numerictype info from the left-most fi and set the fimath accordingly
if isfi(a)
    T = eml_typeof(a);
elseif isfi(b)
    T = eml_typeof(b);
end    
F = fimath('SumMode',       'SpecifyPrecision',...
           'SumWordLength', T.WordLength,...
           'SumSlope',      T.Slope,...
           'SumBias',       T.Bias,...
           'RoundMode',     roundmode,...
           'OverflowMode',  overflowmode,...
           'CastBeforeSum', true);

% Now create some temporary fis that have the fimath F
% and add then to create the output
if isfi(a) && isfi(b)
    Ta = eml_typeof(a);
    Tb = eml_typeof(b);
    a1 = eml_cast(a,Ta,F);
    b1 = eml_cast(b,Tb,F);
    if coder.const(isequal(mode,'pos'))
       c1 = a1 + b1;
    else
       c1 = a1 - b1;
    end
    c = eml_fimathislocal(c1,false);
elseif isfi(a) && ~isfi(b)
    Ta = eml_typeof(a);
    a1 = eml_cast(a,Ta,F);
    b1 = eml_cast(b,T,F);
    if coder.const(isequal(mode,'pos'))
       c1 = a1 + b1;
    else
       c1 = a1 - b1;
    end   
    c = eml_fimathislocal(c1,false);
elseif ~isfi(a) && isfi(b)
    a1 = fi(a,T,F);
    Tb = eml_typeof(b);
    b1 = eml_cast(b,Tb,F);
    if coder.const(isequal(mode,'pos'))
       c1 = a1 + b1;
    else
       c1 = a1 - b1;
    end
    c = eml_fimathislocal(c1,false);
end
