%  // clang-format off
%
%  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
%
%  Use of this source code is governed by a BSD-style license
%  that can be found in the LICENSE file in the root of the source
%  tree. An additional intellectual property rights grant can be found
%  in the file PATENTS.  All contributing project authors may
%  be found in the AUTHORS file in the root of the source tree.
%

function outStruct = parse_delay_file(file)

fid = fopen(file, 'rb');
if fid == -1
    error('Cannot open file %s', file);
end

textline = fgetl(fid);
if ~strncmp(textline, '#!NetEQ_Delay_Logging', 21)
    error('Wrong file format');
end

ver = sscanf(textline, '#!NetEQ_Delay_Logging%d.%d');
if ~all(ver == [2; 0])
    error('Wrong version of delay logging function')
end


start_pos = ftell(fid);
fseek(fid, -12, 'eof');
textline = fgetl(fid);
if ~strncmp(textline, 'End of file', 21)
    error('File ending is not correct. Seems like the simulation ended abnormally.');
end

fseek(fid,-12-4, 'eof');
Npackets = fread(fid, 1, 'int32');
fseek(fid, start_pos, 'bof');

rtpts = zeros(Npackets, 1);
seqno = zeros(Npackets, 1);
pt = zeros(Npackets, 1);
plen = zeros(Npackets, 1);
recin_t = nan*ones(Npackets, 1);
decode_t = nan*ones(Npackets, 1);
playout_delay = zeros(Npackets, 1);
optbuf = zeros(Npackets, 1);

fs_ix = 1;
clock = 0;
ts_ix = 1;
ended = 0;
late_packets = 0;
fs_now = 8000;
last_decode_k = 0;
tot_expand = 0;
tot_accelerate = 0;
tot_preemptive = 0;

while not(ended)
    signal = fread(fid, 1, '*int32');
    
    switch signal
        case 3 % NETEQ_DELAY_LOGGING_SIGNAL_CLOCK
            clock = fread(fid, 1, '*float32');
            
            % keep on reading batches of M until the signal is no longer "3"
            % read int32 + float32 in one go
            % this is to save execution time
            temp = [3; 0];
            M = 120;
            while all(temp(1,:) == 3)
                fp = ftell(fid);
                temp = fread(fid, [2 M], '*int32');
            end
            
            % back up to last clock event
            fseek(fid, fp - ftell(fid) + ...
                (find(temp(1,:) ~= 3, 1 ) - 2) * 2 * 4 + 4, 'cof');
            % read the last clock value
            clock = fread(fid, 1, '*float32');
            
        case 1 % NETEQ_DELAY_LOGGING_SIGNAL_RECIN
            temp_ts = fread(fid, 1, 'uint32');
            
            if late_packets > 0
                temp_ix = ts_ix - 1;
                while (temp_ix >= 1) && (rtpts(temp_ix) ~= temp_ts)
                    % TODO(hlundin): use matlab vector search instead?
                    temp_ix = temp_ix - 1;
                end
                
                if temp_ix >= 1
                    % the ts was found in the vector
                    late_packets = late_packets - 1;
                else
                    temp_ix = ts_ix;
                    ts_ix = ts_ix + 1;
                end
            else
                temp_ix = ts_ix;
                ts_ix = ts_ix + 1;
            end
            
            rtpts(temp_ix) = temp_ts;
            seqno(temp_ix) = fread(fid, 1, 'uint16');
            pt(temp_ix) = fread(fid, 1, 'int32');
            plen(temp_ix) = fread(fid, 1, 'int16');
            recin_t(temp_ix) = clock;
            
        case 2 % NETEQ_DELAY_LOGGING_SIGNAL_FLUSH
            % do nothing
            
        case 4 % NETEQ_DELAY_LOGGING_SIGNAL_EOF
            ended = 1;
            
        case 5 % NETEQ_DELAY_LOGGING_SIGNAL_DECODE
            last_decode_ts = fread(fid, 1, 'uint32');
            temp_delay = fread(fid, 1, 'uint16');
            
            k = find(rtpts(1:(ts_ix - 1))==last_decode_ts,1,'last');
            if ~isempty(k)
                decode_t(k) = clock;
                playout_delay(k) = temp_delay + ...
                    5 *  fs_now / 8000; % add overlap length
                last_decode_k = k;
            end
            
        case 6 % NETEQ_DELAY_LOGGING_SIGNAL_CHANGE_FS
            fsvec(fs_ix) = fread(fid, 1, 'uint16');
            fschange_ts(fs_ix) = last_decode_ts;
            fs_now = fsvec(fs_ix);
            fs_ix = fs_ix + 1;
            
        case 7 % NETEQ_DELAY_LOGGING_SIGNAL_MERGE_INFO
            playout_delay(last_decode_k) = playout_delay(last_decode_k) ...
                + fread(fid, 1, 'int32');
            
        case 8 % NETEQ_DELAY_LOGGING_SIGNAL_EXPAND_INFO
            temp = fread(fid, 1, 'int32');
            if last_decode_k ~= 0
                tot_expand = tot_expand + temp / (fs_now / 1000);
            end                
            
        case 9 % NETEQ_DELAY_LOGGING_SIGNAL_ACCELERATE_INFO
            temp = fread(fid, 1, 'int32');
            if last_decode_k ~= 0
                tot_accelerate = tot_accelerate + temp / (fs_now / 1000);
            end                

        case 10 % NETEQ_DELAY_LOGGING_SIGNAL_PREEMPTIVE_INFO
            temp = fread(fid, 1, 'int32');
            if last_decode_k ~= 0
                tot_preemptive = tot_preemptive + temp / (fs_now / 1000);
            end                
            
        case 11 % NETEQ_DELAY_LOGGING_SIGNAL_OPTBUF
            optbuf(last_decode_k) = fread(fid, 1, 'int32');
            
        case 12 % NETEQ_DELAY_LOGGING_SIGNAL_DECODE_ONE_DESC
            last_decode_ts = fread(fid, 1, 'uint32');
            k = ts_ix - 1;
            
            while (k >= 1) && (rtpts(k) ~= last_decode_ts)
                % TODO(hlundin): use matlab vector search instead?
                k = k - 1;
            end
            
            if k < 1
                % packet not received yet
                k = ts_ix;
                rtpts(ts_ix) = last_decode_ts;
                late_packets = late_packets + 1;
            end
            
            decode_t(k) = clock;
            playout_delay(k) = fread(fid, 1, 'uint16') + ...
                5 *  fs_now / 8000; % add overlap length
            last_decode_k = k;
             
    end
    
end


fclose(fid);

outStruct = struct(...
    'ts', rtpts, ...
    'sn', seqno, ...
    'pt', pt,...
    'plen', plen,...
    'arrival', recin_t,...
    'decode', decode_t,...
    'fs', fsvec(:),...
    'fschange_ts', fschange_ts(:),...
    'playout_delay', playout_delay,...
    'tot_expand', tot_expand,...
    'tot_accelerate', tot_accelerate,...
    'tot_preemptive', tot_preemptive,...
    'optbuf', optbuf);
