function y = sim2fi(intarray, varargin)
% MATLAB Code Generation Library Function

%#codegen

%   Copyright 2012-2014 The MathWorks, Inc.

coder.extrinsic('eml_sim2fi_getNType');
coder.extrinsic('eml_is64BitLongPlatform');

coder.internal.prefer_const(varargin);

% Note: due to MATLAB Coder's limitation, 
%  embedded.numerictype input is not supported by coder.Type
% the ONLY supported signature is
% A = SIM2FI(IntArray, Signed, WordLength, FractionLength)

% So fi double, fi single and scaled double will not be supported until 
% embedded.numerictype is supported by coder.Type 
nt = coder.const(eml_sim2fi_getNType(varargin{:}));

is64BitArray = coder.const(strcmpi(class(intarray), 'uint64') || ...
                         strcmpi(class(intarray), 'int64'));
isUint64Array = coder.const(strcmpi(class(intarray), 'uint64'));

isUint32Array = coder.const(strcmpi(class(intarray), 'uint32'));
is32BitArray = coder.const(strcmpi(class(intarray), 'uint32') || ...
                         strcmpi(class(intarray), 'int32'));

is16BitArray = coder.const(strcmpi(class(intarray), 'uint16') || ...
                         strcmpi(class(intarray), 'int16'));

is8BitArray = coder.const(strcmpi(class(intarray), 'uint8') || ...
                         strcmpi(class(intarray), 'int8'));

if  coder.const(eml_is64BitLongPlatform)
    %% platforms with 64-bit long
    if nt.WordLength < 65        
        % single word real or complex array. one chunk per element
        if eml_ambiguous_types
            y = eml_not_const(zeros(size(intarray)));            
            return;
        end
        
        % error out if input array WL is smaller than nt.WL
        isInWL_LT_OutWL = false;
        if nt.WordLength>32 && ~is64BitArray            
            isInWL_LT_OutWL = true;
        elseif nt.WordLength>16 && (is16BitArray || is8BitArray)
            isInWL_LT_OutWL = true;
        elseif nt.WordLength>8 && is8BitArray            
            isInWL_LT_OutWL = true;
        end        
        eml_invariant(~isInWL_LT_OutWL, 'fixed:sim2fi:SWCodeGenIntArrayWLMustNotLTOutWL');
        
        if (nt.FractionLength == 0)
            y =  fi(intarray, nt);
        else
            if nt.SignednessBool                   
                chunk = fi(intarray, true, nt.WordLength, 0);
            else
                chunk = fi(intarray, false, nt.WordLength, 0);
            end
            y = reinterpretcast(chunk, nt); 
        end   
    else
        eml_invariant(isUint64Array, 'fixed:sim2fi:intarrayNotUint64');
        % multi-word with 2 chunks, must <=128 bits for code gen
        yIdx = 1; uIdx = 1;
        numU64Chunk = 2;  
        if eml_ambiguous_types
            y = zeros(numel(intarray)/numU64Chunk, 1);
            sz = size(intarray);
            sz(1) = sz(1)/numU64Chunk;
            y = reshape(y, sz);
            return;
        else
            y = fi(zeros(numel(intarray)/numU64Chunk, 1), nt);
        end
        
        while uIdx <= numel(intarray)            
            % 2 chunks with WL in [65, 128]
            chunk = fi(intarray(uIdx));
            chunkMS = fi(intarray(uIdx+1), false, nt.WordLength-64, 0);
            if isreal(intarray)
                tmp = bitconcat(chunkMS, chunk); 
            else
                tmpRe = bitconcat(real(chunkMS), real(chunk));
                tmpIm = bitconcat(imag(chunkMS), imag(chunk));
                tmp = complex(tmpRe, tmpIm);
            end         
            uIdx = uIdx +2; 
            
            y(yIdx) = reinterpretcast(tmp, nt);
            yIdx = yIdx + 1;
        end %while
        
        sz = size(intarray);
        sz(1) = sz(1)/numU64Chunk;
        y = reshape(y, sz);
        
    end % if nt.WordLength < 65  
    
else
    %%  platforms with 32-bit long 
    if nt.WordLength < 33        
        % single word real or complex array. one chunk per element
        if eml_ambiguous_types
            y = eml_not_const(zeros(size(intarray)));            
            return;
        end
        
        isInWL_LT_OutWL = false;
        if nt.WordLength>16 && ~is32BitArray            
            isInWL_LT_OutWL = true;
        elseif nt.WordLength>8 && is8BitArray
            isInWL_LT_OutWL = true;
        end
        eml_invariant(~isInWL_LT_OutWL, 'fixed:sim2fi:SWCodeGenIntArrayWLMustNotLTOutWL');
        
        if (nt.FractionLength == 0)
            y =  fi(intarray, nt);
        else
            if nt.SignednessBool                   
                chunk = fi(intarray, true, nt.WordLength, 0);
            else
                chunk = fi(intarray, false, nt.WordLength, 0);
            end
            y = reinterpretcast(chunk, nt); 
        end   
    else
        % multi-word with 2-4 chunks, must <=128 bits for code gen
        yIdx = 1; uIdx = 1;
        numU32Chunk = ceil(bitsra(nt.WordLength, 5));
        eml_invariant(isUint32Array, 'fixed:fi:intarrayNotUint32');
         if eml_ambiguous_types
            y = zeros(numel(intarray)/numU32Chunk, 1);
            sz = size(intarray);
            sz(1) = sz(1)/numU32Chunk;
            y = reshape(y, sz);
            return;
         else
             y = fi(zeros(numel(intarray)/numU32Chunk, 1), nt);
         end
        
        while uIdx <= numel(intarray)
            if nt.WordLength < 65
                % 2 chunks with WL in [33, 64]
                chunk = fi(intarray(uIdx));
                chunkMS = fi(intarray(uIdx+1), false, nt.WordLength-32, 0);
                if isreal(intarray)
                    tmp = bitconcat(chunkMS, chunk); 
                else
                    tmpRe = bitconcat(real(chunkMS), real(chunk));
                    tmpIm = bitconcat(imag(chunkMS), imag(chunk));
                    tmp = complex(tmpRe, tmpIm);
                end         
                uIdx = uIdx +2; 
            elseif nt.WordLength < 97
                % 3 chunks with WL in [66, 96]
                chunk = fi(intarray(uIdx:uIdx+1)); %numU32Chunk-1
                chunkMS = fi(intarray(uIdx+2), false, nt.WordLength-64, 0); % most significant chunk
                if isreal(intarray)
                    tmp = bitconcat(chunkMS, chunk(2), chunk(1)); 
                else
                    chunkRe = real(chunk);
                    tmpRe = bitconcat(real(chunkMS),chunkRe(2), chunkRe(1));
                    chunkIm = imag(chunk);
                    tmpIm = bitconcat(imag(chunkMS),chunkIm(2), chunkIm(1));
                    tmp = complex(tmpRe, tmpIm);
                end
                uIdx = uIdx + 3;
            else %nt.WordLength < 129
                 % 4 chunks with WL in [97, 128]
                chunk = fi(intarray(uIdx:uIdx+2));
                chunkMS = fi(intarray(uIdx+3), false, nt.WordLength-96, 0); % most significant chunk
                if isreal(intarray)
                    tmp = bitconcat(chunkMS, chunk(3), chunk(2), chunk(1)); 
                else
                    chunkRe = real(chunk);
                    tmpRe = bitconcat(real(chunkMS),chunkRe(3),chunkRe(2), chunkRe(1));
                    chunkIm = imag(chunk);
                    tmpIm = bitconcat(imag(chunkMS),chunkIm(3),chunkIm(2), chunkIm(1));
                    tmp = complex(tmpRe, tmpIm);
                end         
                uIdx = uIdx + 4;  
            end % if
            y(yIdx) = reinterpretcast(tmp, nt);
            yIdx = yIdx + 1;
        end %while
        
        sz = size(intarray);
        sz(1) = sz(1)/numU32Chunk;
        y = reshape(y, sz);
    end
end
