function yout = median(x, dimx)%#codegen
%MEDIAN Median value.
%
%   Y = MEDIAN(X) computes the median value of the elements in FI array X along
%   its first non-singleton dimension.
%
%   Y = MEDIAN(X, DIM) computes the median value of the elements in FI array X 
%   along dimension DIM.

%   Copyright 2009-2014 The MathWorks, Inc.

eml_invariant(nargin > 0, 'fixed:coder:notEnoughInputArguments');

isnumin1 = (nargin == 1);
if isnumin1
    
    dimx = 1;
end
eml_statop_input_and_index_checks(x, 'median', dimx);
eml_invariant(isreal(x), 'fixed:fi:unsupportedComplexInput', 'MEDIAN');
dim = eml_statop_validate_and_get_dim(x, isnumin1, dimx);

if dim > coder.internal.ndims(x)    
    y = x;
    yout = eml_fimathislocal(y,false);
    return;
end

sz = size(x);
sz(dim) = 1;
ty = numerictype(x);
tmp = coder.nullcopy(eml_expand(coder.internal.scalarEg(x),sz));
if isfloat(x)
    
    xtemp = eml_cast(x, eml_fi_getDType(x));
    xmedian = median(xtemp, eml_cast(dim,'double'));
    y = eml_cast(xmedian, ty);
elseif isempty(x) && eml_is_const(isempty(x)) 
    
    y = eml_statop_empty_handling(x, isnumin1, ty, dim);
elseif isscaleddouble(x)
    xmedian = median(double(x),double(dim));
    y = eml_cast(xmedian,ty);
elseif isscalar(tmp) && eml_is_const(isscalar(tmp))
    
    y = vectormedian(x);
else
    
    vlen = size(x,dim);
    y = tmp;
    
    vwork = coder.nullcopy(eml_expand(coder.internal.scalarEg(x),[vlen,1]));
    vstride = coder.internal.prodsize(x,'below',dim);
    vspread = coder.internal.indexTimes(coder.internal.indexMinus(vlen,1),vstride);
    npages = coder.internal.prodsize(x,'above',dim);
    i2 = zeros(coder.internal.indexIntClass);
    iy = zeros(coder.internal.indexIntClass);
    for i = 1:npages
        
        i1 = i2;
        i2 = coder.internal.indexPlus(i2,vspread);
        for j = 1:vstride
            
            i1 = coder.internal.indexPlus(i1,1);
            i2 = coder.internal.indexPlus(i2,1);
            % copy x(i1:vstride:i2) to vwork
            ix = i1;
            for k = 1:vlen
                
                vwork(k) = x(ix);
                ix = coder.internal.indexPlus(ix,vstride);
            end
            % Calculate median and store in y
            iy = coder.internal.indexPlus(iy,1);
            y(iy) = vectormedian(vwork);
        end
    end
end

yout = eml_fimathislocal(y,false);


function m = vectormedian(v)

coder.extrinsic('emlGetNTypeForPlus');

maxWL = getFixedPointWidthLimit();
vlen = numel(v);
midm1 = coder.internal.indexDivide(vlen,2);
mid = coder.internal.indexPlus(midm1,1);
evenlength = (vlen == coder.internal.indexTimes(midm1,2));

v = sort(v);
m = coder.internal.scalarEg(v);
tv = coder.const(numerictype(v));

if evenlength
    
    elem1 = v(midm1);
    elem2 = v(mid);    
    fm = coder.const(eml_fimath(v));
    tc = coder.const(emlGetNTypeForPlus(tv,tv,fm,maxWL));
    c = eml_plus(elem1, elem2, tc, fm);
    tcby2 = coder.const(numerictype(tc,'FractionLength',(tc.FractionLength+1)));    
    cscale = reinterpretcast(c, tcby2);
    m(:) = cscale;
else
    
    m = v(mid);
end
