classdef helperBLEMeshQueue < handle
%helperBLEMeshQueue Queuing of packets in Bluetooth mesh node
%   MESHQUEUE = helperBLEMeshQueue(QUEUESIZE) creates a queue with
%   specified QUEUESIZE.
%
%   QUEUESIZE is an integer, indicating size of the queue.
%
%   helperBLEMeshQueue methods:
%
%   enQueue  - Push data into queue
%   deQueue  - Pop data from queue
%   isEmpty  - Check whether queue is empty or not
%   isFull   - Check whether queue is full or not
%   hasValue - Check whether specified value is present in queue or not

%   Copyright 2019 The MathWorks, Inc.

%#codegen

properties (SetAccess = private)
    %Queue Buffer to store data
    Queue
    
    %QueueIndex Index of queue
    QueueIndex
    
    %QueueSize Maximum size of queue
    QueueSize
end

properties (Constant, Hidden)
    %MaxElementSize Maximum size of element in queue
    MaxElementSize = 50
end

properties (Hidden, SetAccess = private)
    %QueueElementLength List of lengths of each element in queue
    QueueElementLength
end
    
methods
    % Constructor
    function obj = helperBLEMeshQueue(queueSize)
        % Validate queue size
        validateattributes(queueSize, {'numeric'}, ...
        {'scalar', 'integer', 'positive'}, mfilename, 'queueSize');
        % Create a queue (cell array)
        obj.Queue = cell(queueSize, 1);
        obj.QueueElementLength = zeros(queueSize, 1);
        % Initialize for codegen
        for idx = 1:numel(obj.Queue)
            obj.Queue{idx} = zeros(obj.MaxElementSize, 1);
        end
        % Update queue size
        obj.QueueSize = queueSize;
        % Initialize queue index
        obj.QueueIndex = 1;
    end
    
    % Push data into queue
    function flag = enQueue(obj, data)
        % Initialize
        flag = true;
        
        % Queue can accommodate more data
        if ~obj.isFull
            % For codegen
            dataLen = numel(data);
            paddedData = zeros(obj.MaxElementSize, 1);
            paddedData(1:dataLen) = data;
            % Update queue
            obj.QueueElementLength(obj.QueueIndex) = dataLen;
            obj.Queue{obj.QueueIndex} = paddedData;
            obj.QueueIndex = obj.QueueIndex + 1;
            
        % Queue is full
        else
            flag = false;
        end
    end
    
    % Pop data from queue
    function [flag, data] = deQueue(obj)
        % Initialize
        flag = true;
        data = zeros(1, 0);
        
        % Queue is non-empty
        if ~obj.isEmpty
            % Dequeue data from queue
            dataLen = obj.QueueElementLength(1);
            paddedData = obj.Queue{1};
            data = paddedData(1:dataLen);
            % Update the queue
            for idx = 1:(obj.QueueSize - 1)
                obj.QueueElementLength(idx) = obj.QueueElementLength(idx+1);
                obj.Queue{idx} = obj.Queue{idx+1};
            end
            obj.QueueElementLength(obj.QueueSize) = 0;
            obj.Queue{obj.QueueSize} = zeros(50, 1);
            % Update the queue index
            obj.QueueIndex = obj.QueueIndex - 1;
            
        % Queue is empty
        else
            flag = false;
        end
    end
    
    % Check whether queue is empty or not
    function flag = isEmpty(obj)
        flag = (obj.QueueIndex <= 1);
    end
    
    % Check whether queue is full or not
    function flag = isFull(obj)
        flag = (obj.QueueIndex > obj.QueueSize);
    end
    
    % Check whether specified value is present in queue or not
    function flag = hasValue(obj, value)
        flag = false;
        if obj.QueueIndex > 1
            for idx = 1:(obj.QueueIndex - 1)
                qValueLen = obj.QueueElementLength(idx);
                qValue = obj.Queue{idx}(1:qValueLen);
                if isequal(qValue, value)
                    flag = true;
                end
            end
        end
    end
end
end
