function c = divide(tc0,a0,b0)
% MATLAB Code Generation function the fi/numerictype divide operation

% Copyright 2002-2017 The MathWorks, Inc.
%#codegen

coder.extrinsic('emlGetBestPrecForMxArray');
eml_allow_mx_inputs;

eml_invariant(nargin==3, 'fixed:coder:notEnoughInputArguments');

% Verify that the first input is an embedded.numerictype, is not slope/bias scaled, and has Signed and Scaling specified.
eml_invariant(isnumerictype(tc0), ...
    'fixed:coder:divideNotDefinedFor1stArgType',class(tc0));

eml_invariant((isreal(a0) && isreal(b0)) || (~isslopebiasscaled(tc0)), ... 
    'fixed:fi:noOpLeadingToComplexSlopeBias');

% Verify that tc0 is not slope-bias scaled
eml_invariant(~isslopebiasscaled(tc0), ...
    'fixed:fi:binaryPointOnlyMath', 'DIVIDE');

% Verify that the signedness of tc0 is not auto
eml_invariant(~coder.const(strcmpi(get(tc0,'Signedness'),'Auto')),...
    'fixed:fi:divideNonSpecifiedSign');

% Verify that the scaling of tc0 is not unspecified
eml_invariant(~tc0.isscalingunspecified, ...
    'fixed:fi:divideNonSpecifiedScaling');

% Verify that a0 and b0 must be numeric
eml_invariant(isnumeric(a0), 'fixed:coder:divide_T_a_b_aMustBeNumeric');
eml_invariant(isnumeric(b0), 'fixed:coder:divide_T_a_b_bMustBeNumeric');

% Check for ambiguous types and return with the correct size output
if eml_ambiguous_types && ~isfi(a0) && ~isfi(b0) 
    c = eml_rdivide(a0,b0);
    return;
elseif eml_ambiguous_types && (isfi(a0) || isfi(b0))
    if isfi(a0)
        ftemp = eml_fimath(a0);
    elseif isfi(b0)
        ftemp = eml_fimath(b0);
    end
    
    if numel(a0) > numel(b0)
        c = eml_cast(a0,tc0,ftemp);
    else
        c = eml_cast(b0,tc0,ftemp);
    end
    return;
end

if isfixed(tc0) && ...
    (isfi(a0) && isscaleddouble(a0) || ...
     isfi(b0) && isscaleddouble(b0))
    % Propagate ScaledDouble type
    tc = numerictype(tc0,'DataType','ScaledDouble');
else
    tc = tc0;
end

if ( (isfi(a0) && isscaledtype(a0)) || ...
     (isfi(b0) && isscaledtype(b0)) )
    % Fixed FI

    % TODO: Add code to parse through the inputs tc, a0 & b0 and error if necessary
    if isfi(a0) && ~isfi(b0) % fi ./ non-fi
        fixedOpFloatYieldsFloating = coder.const(strcmpi(get(fimath(a0),'FixedOpFloatingYields'),'Floating'));
        if isa(b0,'double') && fixedOpFloatYieldsFloating
            c = double(a0) ./ b0;
            return
        elseif isa(b0,'single') && fixedOpFloatYieldsFloating
            c = single(a0) ./ b0;
            return
        end
        ta = eml_typeof(a0);
        % Verify that scaling is not slope-bias
        biasA = coder.const(get(ta,'Bias'));
        safA      = coder.const(get(ta,'SlopeAdjustmentFactor'));
        isslopebias_a = coder.const((biasA~=0)||(safA~=1));        
        eml_invariant(coder.const(isslopebias_a==0), ...
            'fixed:fi:binaryPointOnlyMath', 'DIVIDE');
        f = eml_fimath(a0);
        eml_check_div_fimath(f);
        a = a0; 
        cHasLocalFimath = coder.const(eml_fimathislocal(a0));
        if isinteger(b0)
            % Don't auto-scale built-in integers
            b = fi(b0);
            tb = eml_typeof(b); %#ok<NASGU>
        else
            % Get best precision numerictype for b
            eml_invariant(eml_is_const(b0), ...
                'fixed:coder:divideFi_NonFi_NonFiMustBeConstant');
            tb = coder.const(emlGetBestPrecForMxArray(b0,ta));
            b = eml_cast(b0,tb,f);
        end
    elseif ~isfi(a0) && isfi(b0) % non-fi ./ fi
        fixedOpFloatYieldsFloating = coder.const(strcmpi(get(fimath(b0),'FixedOpFloatingYields'),'Floating'));
        if isa(a0,'double') && fixedOpFloatYieldsFloating
            c = a0 ./ double(b0);
            return
        elseif isa(a0,'single') && fixedOpFloatYieldsFloating
            c = a0 ./ single(b0);
            return
        end

        tb = eml_typeof(b0);
        % Verify that scaling is not slope-bias
        biasB = coder.const(get(tb,'Bias'));
        safB      = coder.const(get(tb,'SlopeAdjustmentFactor'));
        isslopebias_b = coder.const((biasB~=0)||(safB~=1));        
        eml_invariant(coder.const(isslopebias_b==0), ...
            'fixed:fi:binaryPointOnlyMath', 'DIVIDE');
        f = eml_fimath(b0);
        eml_check_div_fimath(f);
        b = b0;
        cHasLocalFimath = coder.const(eml_fimathislocal(b0));
        if isinteger(a0)
            % Don't auto-scale built-in integers
            a = fi(a0);
            ta = eml_typeof(a); %#ok<NASGU>
        else
            % Get best precision numerictype for a
            eml_invariant(eml_is_const(a0), ...
                'fixed:coder:divideNonFi_Fi_NonFiMustBeConstant');
            ta = coder.const(emlGetBestPrecForMxArray(a0,tb));
            a = eml_cast(a0,ta,f);
        end
    elseif ~isfi(a0) && ~isfi(b0)  %%ck: is this redundant? is both are
                                   %non-fi, this fcn would not be called!
        c = eml_rdivide(a0,b0);
        return;
    else % fi ./ fi
         % Obtain the eml_typeofs of a & b
        ta = eml_typeof(a0); tb = eml_typeof(b0);
        % Verify that scalings are not slope-bias
        biasA = coder.const(get(ta,'Bias'));
        safA      = coder.const(get(ta,'SlopeAdjustmentFactor'));        
        biasB = coder.const(get(tb,'Bias'));
        safB      = coder.const(get(tb,'SlopeAdjustmentFactor'));
        isslopebias_a_or_b = coder.const((biasA~=0)||(safA~=1)||(biasB~=0)||(safB~=1));        
        eml_invariant(coder.const(isslopebias_a_or_b==0), ...
            'fixed:fi:binaryPointOnlyMath', 'DIVIDE');
        % Get the fimath
        % Check the fimathislocal property and determine the output fimath
        aHasLocalFimath = coder.const(eml_fimathislocal(a0));
        bHasLocalFimath = coder.const(eml_fimathislocal(b0));
        if aHasLocalFimath
            f = eml_fimath(a0); % divide takes A's local fimath over B's
        else
            f = eml_fimath(b0);
        end

        cHasLocalFimath = coder.const(aHasLocalFimath || bHasLocalFimath);
        eml_check_div_fimath(f);
        a = a0; b = b0;
    end

    if ~isreal(a) && isreal(b) % complex/real
        reala = real(a); imaga = imag(a);
        if eml_is_const(b0) && all(b(:)~=0)
            % The denominator is constant and non-zero, so call efficient divide without divide-by-zero protection
            realc = eml_rdivide(reala,b,tc,f);
            imagc = eml_rdivide(imaga,b,tc,f);
        else
            % The denominator is not constant or contains a zero, so divide with divide-by-zero protection.
            realc = divide_with_divide_by_zero_protection(reala,b,tc,f);
            imagc = divide_with_divide_by_zero_protection(imaga,b,tc,f);
        end
        c = eml_fimathislocal(complex(realc,imagc),cHasLocalFimath);
    elseif ~isreal(b) % complex/complex & real/complex
        eml_invariant(false, ...
            'fixed:fi:DivideNoComplexDivisor');
    else % real/real
         % tc is the numerictype of the divide
        if eml_is_const(b0) && all(b(:)~=0)
            % The denominator is constant and non-zero, so call efficient divide without divide-by-zero protection
            c = eml_fimathislocal(eml_rdivide(a,b,tc,f),cHasLocalFimath);
        else
            % The denominator is not constant or contains a zero, so divide with divide-by-zero protection.
            c = eml_fimathislocal(divide_with_divide_by_zero_protection(a,b,tc,f),cHasLocalFimath);
        end
    end
elseif ( isfi(a0) && isfloat(a0) ) || ...
        ( isfi(b0) && isfloat(b0) )
    % True Double or True Single FI

    % call MATLAB divide directly
    check4constNonFI   = false; % non-FI need not be constant
    check4numericData  = true;  % non-FI must be numeric
    check4sameDatatype = false; % The datatypes of two inputs need not be
                                % same
                                % As check4constNonFI = false, the operation name (third input argument)
                                % will not be used
    [ain,bin]          = eml_fi_cast_two_inputs(a0,b0,'dummy',check4constNonFI,...
                                                check4numericData,check4sameDatatype);
    [t,f]              = eml_fi_get_numerictype_fimath(a0,b0);

    if ~isreal(a0) && isreal(b0) % complex/real
        reala = real(ain); imaga = imag(ain);
        if eml_is_const(b0) && all(bin(:)~=0)
            % The denominator is constant and non-zero, so call efficient divide without divide-by-zero protection
            realc = eml_rdivide(reala,bin,t,f);
            imagc = eml_rdivide(imaga,bin,t,f);
        else
            % The denominator is not constant or contains a zero, so divide with divide-by-zero protection.
            realc = divide_with_divide_by_zero_protection(reala,bin,t,f);
            imagc = divide_with_divide_by_zero_protection(imaga,bin,t,f);
        end
        c = complex(realc,imagc);
    elseif ~isreal(b0) % complex/complex & real/complex
        eml_invariant(false, ...
            'fixed:fi:DivideNoComplexDivisor');
    else % real/real
         % tc is the numerictype of the divide
        if eml_is_const(b0) && all(bin(:)~=0)
            % The denominator is constant and non-zero, so call efficient divide without divide-by-zero protection
            c = eml_rdivide(ain,bin,t,f);
        else
            % The denominator is not constant or contains a zero, so divide with divide-by-zero protection.
            c = divide_with_divide_by_zero_protection(ain,bin,t,f);
        end
    end
    
elseif isfloat(a0) || isfloat(b0)
    
    % call MATLAB divide directly
    c = eml_rdivide(a0,b0);

else
    % FI datatype not supported
    eml_fi_assert_dataTypeNotSupported('DIVIDE');
end
end % divide

function c = divide_with_divide_by_zero_protection(a,b,T,F)
%DIVIDE_WITH_DIVIDE_BY_ZERO_PROTECTION Division with divide-by-zero protection.
    % Check sizes
    eml_invariant(isscalar(a) || isscalar(b) || isequal(size(a),size(b)),'fixed:fi:DimAgree');

    % Initialize the output with the correct size and type.
    ZERO = zeros('like',fi([],T,F));
    if isempty(a) || isscalar(b)
        c = eml_expand(ZERO,size(a));
    else
        c = eml_expand(ZERO,size(b));
    end
    if ~isempty(a) && ~isempty(b)
        % This indexing does scalar expansion, and works for variable-sized
        % inputs. You need to pre-declare these variables instead of using
        % numel(c), etc. directly for it to work in codegen and purely
        % integer code.
        %
        % N is the number of elements in the output, c.
        N = cast(max(numel(a),numel(b)),coder.internal.indexIntClass);
        % i is the index of the numerator
        i = zeros(1,1,coder.internal.indexIntClass);
        % j is the index of the denominator
        j = zeros(1,1,coder.internal.indexIntClass);
        for n = 1:N
            i(:) = min(numel(a),n);
            j(:) = min(numel(b),n);
            if b(j) == 0
                % Denominator is zero.
                if a(i) < 0
                    % Set the output to the lower bound of the range when
                    % the numerator is negative and the denominator is
                    % zero.
                    c(n) = lowerbound(c);
                else
                    % Set the output to the upper bound of the range when
                    % the numerator is positive or zero and the denominator
                    % is zero.  This matches Simulink fixed-point behavior.
                    % MATLAB int8(0)./int8(0) returns 0.
                    c(n) = upperbound(c);
                end
            else
                % Denominator is not zero
                c(n) = eml_rdivide(a(i),b(j),T,F);
            end
        end
    end
    % Nothing to be done for else case.  The output is empty and has already been defined.
    
end % divide_with_divide_by_zero_protection

%--------------------------------------------------------------------------------------------
% LocalWords: tc tc0 eml_typeofs scalings
% LocalWords: Prec typeofs siz
