function tripEventSummary = processMDF(fname, chName, thdValue, thdDuration)
% processMDF Execute data collection and event detection for MDF example.
%
% This function finds and reports "events" in a time based signal.
% This is accomplished by applying user supplied event detection criteria
% to the input signal and is designed to be compatible with Tall Arrays.
%
% Copyright 2018 The MathWorks, Inc.

%% Read data from the MDF file.
mdfObj = mdf(fname);

%% Determine the channel group index.
chInfo = channelList(mdfObj, chName);

%% Test to see if the specified channel exists in the MDF file.
% If yes, read it and proceed with the event detection work.
% If no, go on to the next MDF file.

% The channel requested does not exist in this MDF file.
if isempty(chInfo)
    return
else
    % Read the data from the specified channel group.
    ttIn = read(mdfObj, chInfo);
    
    % Reading with a channel list returns a cell array in case of multiple
    % channels being read. In this case, only a single channel is read.
    % Remove the cell array for additional processing.
    ttIn = ttIn{1};
end

%% Pre-processing.
% Make sure the data are sorted in time.
ttIn = sortrows(ttIn,'Time');

% Convert power from W to KW.
ttIn.Power = ttIn.Power ./1000;

%% Retime the timetable to a common time step.
tStart = min(ttIn.Time);
tEnd   = max(ttIn.Time);
T = retime(ttIn,tStart:seconds(0.01):tEnd,'nearest');

%% Apply the threshold criteria for event detection.
eventMsk = (T.(chName) >= thdValue(1)) & (T.(chName) <= thdValue(2));

%% Determine where each event starts and ends.
% Rising edges.
risingEdges  = diff([0;eventMsk]);

% Falling edges.
fallingEdges = diff([eventMsk;0]);

%% Number all of the events.
% Identify the events (all of them). This includes the events "in between"
% the events of interest.
eventArray = cumsum(abs(risingEdges));

% Get rid of the "in between" (even numbered) events.
inBetween_msk = logical(mod(eventArray,2));

% Set the "in between" events to NaN.
eventArray(~inBetween_msk) = NaN;

% Make the event numbers sequential (makes more sense this way).
eventArray(eventArray>0) = (eventArray(eventArray>0) + 1) / 2;

%% Add the event numbers to the timetable.
T.EventNum = repmat(categorical(NaN), height(T), 1);
T.EventNum = categorical(eventArray);

%% Determine which groups qualify as an event of interest.
% Calculate the duration of each event.
[G,GID] = findgroups(T.EventNum);
eventStart    = splitapply(@min, T.Time,G);
eventEnd      = splitapply(@max, T.Time,G);
eventDuration = eventEnd - eventStart;

% Modify the display format.
eventDuration.Format = 'hh:mm:ss';

%% Determine which events qualify (i.e. meet the duration criteria).
% Identify the events (groups) that are longer than the threshold time (i.e., > 1s).
msk = eventDuration >= thdDuration;
qualifiedEventNumbers = double(GID(msk));

%% Add the qualified events to the table.
T.QualifiedEvents = ismember(eventArray, double(qualifiedEventNumbers));

%% Report power statistics.
% Reduce the data to only consider the qualified events.
pData = T(T.QualifiedEvents,:);

% Calculate the mean power during an event.
[qualEventIdx,EventID] = findgroups(pData.EventNum);
meanPower = splitapply(@mean, pData.Power, qualEventIdx);
maxPower  = splitapply(@max, pData.Power, qualEventIdx);
minPower  = splitapply(@min, pData.Power, qualEventIdx);


%% Summarize.
% Build up the summary of what we have accounted for. Table that looks like this:
% FileName   EventNumber   EventDuration   tStart   tEnd   MeanPower_KW
eventStart    = splitapply(@min, pData.Time, qualEventIdx);
eventEnd      = splitapply(@max, pData.Time, qualEventIdx);
eventDuration = eventEnd - eventStart;

% Modify the display format.
eventDuration.Format = 'hh:mm:ss';

% Parse the full file path.
[~,b,c] = fileparts(fname);
fileName = horzcat(b,c);

% Build up the summary table.
tripSummary = table;
tripSummary.FileName      = repmat(categorical(cellstr(fileName)), numel(eventStart), 1);
tripSummary.EventNumber   = EventID;
tripSummary.EventDuration = eventDuration;
tripSummary.EventStart    = eventStart;
tripSummary.EventStop     = eventEnd;
tripSummary.MeanPower_KW  = meanPower;
tripSummary.MaxPower_KW   = maxPower;
tripSummary.MinPower_KW   = minPower;

%% Return the function output.
tripEventSummary = tripSummary;
end
