function out = msaSessionUpdate(NameValueArgs)

% msaSessionUpdate automatically performs update operation on a saved
% Mixed-Signal Analyzer (MSA) session (session mat file) using either a Cadence
% simulation mat file (generated using adeinfo2msa) provided by the user or
% adeInfo database directly from an active Cadence Virtuoso ADE session  .
% After performing the update operation (i.e. refreshing of all waveforms
% in the app) msaSessionUpdate also creates a report based on user's preference.
%
% msaSessionUpdate(NameValueArgs)
%
%PROPERTIES
% There are following options for NameValueArgs:
%
%  sessionFileName - MAT file name for the Mixed-Signal Analyzer session
%  (i.e. MSA session mat file) with configured waveforms and plots that user
%  wants to update. This needs to be provided by the user for the function
%  to work.
%
%  sessionPath - The folder/directory location where MSA session mat file is
%  saved. By default, if working from an active Cadence Virtuoso ADE
%  session the function will look for the session file in maestro/documents
%  folder. Otherwise, it will look in the present working directory.
%
%  updateMatFileName - The name of the mat file having Cadence simulation
%  data. This file will be used to update all the plots in the MSA
%  session. This is required to be provided by the user when not working
%  from an active Cadence Virtuoso ADE session.
%
%  updateMatPath - The folder location where the mat file having cadence
%  simulation data is saved. By default, the function looks for the file in
%  the current directory (pwd).
%
%  reportType - The type of report created at the end of the udpate
%  operation by the function. It should be from one of the following options :
%  'ppt', 'pdf','doc', 'html'. by default, ppt report gets created.
%
%  reportFileName - Name of the file with which the report will be saved.
%
%  reportTitle - Title text that will show up in the report.
%
%  reportPath - The destination folder where report needs to be
%  saved. By default, while workining from an active Cadence Virtuoso ADE
%  session the report will be saved under maestro/documents folder.
%  Otherwise, it will be saved in the present working directory.
%
%  msaVisibility - Option to keep the MSA session visible. by default, 
%  it's 'true'. To perform update in invisible mode set masVisibility to be
%  'false'
%
%EXAMPLES
%
% %update a session mat file 'clockBuffSession.mat' using a simulation
% %mat file named 'Interactive.10.mat'. Also, close the MSA session after
% %the operation
% msaSessionUpdate(sessionFileName='clockBuffSession.mat',updateMatFileName='Interactive.10.mat',msaVisibility=false)
%
% %update a session mat file 'clockBuffSession.mat' using adeInfo databse
% %while working from an active Cadence Virtuoso ADE session . Also,
% create a pdf report
% msaSessionUpdate(sessionFileName='clockBuffSession.mat',reportType='pdf')

% Copyright 2023 The Mathworks, Inc.


arguments
    NameValueArgs.sessionFileName=''; % This needs to be entered by user for script to work
    NameValueArgs.sessionPath=''; % Folder location where the MSA session is saved
    NameValueArgs.updateMatFileName=''; % This needs to be entered by user for script to work
    NameValueArgs.updateMatPath=pwd; % Folder location where the MSA session is saved
    NameValueArgs.reportType='ppt'; %{'ppt','doc','pdf','html'}
    NameValueArgs.reportFileName='';
    NameValueArgs.reportTitle='MSA Report';
    NameValueArgs.reportPath='';
    NameValueArgs.msaVisibility=true; % MSA gui will remain visible by default.
end

if(isempty(NameValueArgs.reportPath))
    try
        adeInfo=evalin('base','adeInfo.loadResult');
        path = adeInfo.adeRDBLocation;
        % Edit path to point to /documents in ADE
        indices = strfind(path,'/');
        concatPath = extractBefore(path,indices(end-2));
        NameValueArgs.reportPath = append(concatPath,'/documents');
    catch
        NameValueArgs.reportPath=pwd;
    end
end

NameValueArgs.reportPath=what(NameValueArgs.reportPath).path;

if(isempty(NameValueArgs.sessionPath))
    try
        adeInfo=evalin('base','adeInfo.loadResult');
        path = adeInfo.adeRDBLocation;
        % Edit path to point to /documents in ADE
        indices = strfind(path,'/');
        concatPath = extractBefore(path,indices(end-2));
        NameValueArgs.sessionPath = append(concatPath,'/documents');
    catch
        NameValueArgs.sessionPath=pwd;
    end
end


if(isempty(NameValueArgs.sessionFileName))
    %error('Valid Mixed-Signal Analyzer (MSA) session file needs to be provided for script to work');
    error(message('msblks:mixedsignalanalyzer:missingMsaSession'));
else
    msaSession=fullfile(NameValueArgs.sessionPath,NameValueArgs.sessionFileName);
    if(~isfile(msaSession))
        error(getString(message('msblks:mixedsignalanalyzer:invalidMsaSession',NameValueArgs.sessionFileName,NameValueArgs.sessionPath)));
    else
        waveExist=0;
        metricExist=0;
        metricsOnly=true;
        sessionInfo=load(msaSession);
        if(~isempty(sessionInfo.mixedSignalAnalysis.DataDB.analysisWaveforms) || ~isempty(sessionInfo.mixedSignalAnalysis.DataDB.analysisMetricNames))
            metricsOnly=false;
        else
            for i=1:length(sessionInfo.mixedSignalAnalysis.Plots)
                switch(length(fieldnames(sessionInfo.mixedSignalAnalysis.Plots{i})))
                    case 3
                        waveExist=1;
                    otherwise
                        metricExist=1;
                end
                if (waveExist==1) % && metricExist==1)
                    metricsOnly=false;
                    break;
                end
            end
        end
    end
end



if(isempty(NameValueArgs.updateMatFileName))
    if(~isunix)
        error(message('msblks:mixedsignalanalyzer:missingMatFile'));
    else
        try
            msaMatFile = tempname; %[tempname, '.mat'];%creates a unique mat filename under /tmp/
            matFilePathTemp=tempdir;
            adeinfo2msa('fileName',msaMatFile,'import2msa',false,'metricsOnly',metricsOnly);
            tempFile=split(msaMatFile,'/');
            msaMatFileName=[tempFile{end},'.mat']; %tempFile{end};
        catch
            error(message('msblks:mixedsignalanalyzer:invalidAdeInfo'));
        end
    end
else

    msaMatFile=fullfile(NameValueArgs.updateMatPath,NameValueArgs.updateMatFileName);
    msaMatFileName=NameValueArgs.updateMatFileName;
    if(~isfile(msaMatFile))
        error(getString(message('msblks:mixedsignalanalyzer:invalidMatFile',NameValueArgs.updateMatFileName,NameValueArgs.updateMatPath)));
    end
    if ispc
        matFilePathTemp=[NameValueArgs.updateMatPath,'\'];
    else
        matFilePathTemp=[NameValueArgs.updateMatPath,'/'];
    end
end

%warning('off','MATLAB:hg:AutoSoftwareOpenGL');


updateRequest={{1,1,1,1,4}};
% get the handle of the MSA app session
msaHandle=msblks.internal.apps.mixedsignalanalyzer.MixedSignalAnalyzerTool(msaSession,NameValueArgs.msaVisibility);
    % msaHandle.View.Toolstrip.appContainer.Visible=true;
    % pause(4);
    % msaHandle.appContainer.WindowMaximized=true;    
    % msaHandle.appContainer.WindowMinimized=true;


%msaHandle.appContainer.WindowMaximized=true;


% readCadenceData method in Model.m is used to perform the update
% operation.

%warning('off','MATLAB:hg:AutoSoftwareOpenGL');

fullPathMatFileName = [matFilePathTemp,msaMatFileName];
database = load(fullPathMatFileName);
if ~isfield(database,'genericDB')

    %  msaHandle.View.Toolstrip.appContainer.Visible=true;
    % pause(4);
    % %msaHandle.appContainer.WindowMaximized=true;    
    % msaHandle.appContainer.WindowMinimized=true;
    msaHandle.Model.readCadenceData(msaMatFileName,matFilePathTemp,updateRequest);
else
    if isfield(database,'fileList')
        fileList = database.fileList; % Get fileList (node names vesus file names) within struct.
        isFileListFromStruct = true; % fileList is from a struct within database (alongside genericDB).
    else
        fileList = [];
        isFileListFromStruct = false; % fileList is NOT from a struct within database.
    end
    if isfield(database,'genericDB')
        database = database.genericDB; % Get genericDB (SimulationsDB object) within struct.
        database.pathToSimulationsDBFileFolder = matFilePathTemp;
        database.fullPathSimulationsDBFileName = fullPathMatFileName;
    end

    if ~isempty(database)
        % Add data to MSA model (Model.m, this file).
        % if isempty(obj.Database)
        %     obj.Database      = database;
        %     obj.Database_Type = 'SimulationsDB';
        % else
        %     obj.Database      = [obj.Database,      database];
        %     obj.Database_Type = [obj.Database_Type, {'SimulationsDB'}];
        % end
        % Store folder and full path of .mat file containing SimulationsDB object.
        % These values:
        % - are (re)set whenever the file is opened.
        % - reflect the current location of the file.
        % - are used for incremental loading of waveforms.
        % - are NOT the same as database.fullPathMatFileName.
        pathname=matFilePathTemp;
        database.pathToSimulationsDBFileFolder = matFilePathTemp;
        database.fullPathSimulationsDBFileName = fullPathMatFileName;

        % Get node names vesus file names from fileList (if it exists).
        % - For incremental loading of waveform data from <m>.<n>.mat files.
        if isempty(fileList)
            % 2nd attempt to get fileList (assuming preliminary implementation format).
            % Get node names vesus file names from fileNameKey.mat (if it exists).
            % - Located in same folder as SimulationsDB object.
            fullPathFileNameKey = [pathname 'fileNameKey.mat'];
            if isfile(fullPathFileNameKey)
                fileNameKey = load(fullPathFileNameKey);
                if isfield(fileNameKey,'fileList')
                    fileList = fileNameKey.fileList;
                end
            end
        end
        if ~isempty(fileList)
            fileListLength = length(fileList);
            fileNames{fileListLength} = []; % Pre-allocate cell array.
            nodeNames{fileListLength} = []; % Pre-allocate cell array.
            for node = 1:fileListLength
                fileNames{node} = fileList{node,1}; % <m>.<n>.mat file name.
                nodeNames{node} = fileList{node,2}; % Corresponding node name for file.
                if ~isFileListFromStruct
                    % Remove folder prefix to isolate file name (if needed).
                    % - Only done if fileList is from fileNameKey.mat (preliminary implementation format).
                    % - NOT done if fileList is from a struct within database alongside genericDB (latest format).
                    index = strfind(fileNames{node},'\'); % Look for backslash delimiter.
                    if isempty(index)
                        index = strfind(fileNames{node},'/'); % Look for slash delimiter.
                    end
                    if ~isempty(index)
                        fileNames{node} = extractAfter(fileNames{node},index); % Get text after delimiter.
                    end
                end
            end
            database.incrementalFiles = fileNames;
            database.incrementalNodes = nodeNames;
            if ~isempty(database.SimulationResultsObjects)
                % Check SimulationsResults object(s) for existence of waveform names.
                % - They should always exist in latest genericDB.mat file.
                % - If not, then they are copied from the <m>.<n>.mat files.
                for resultsObject = 1:length(database.SimulationResultsObjects)
                    simRunObject = database.SimulationResultsObjects{resultsObject};
                    if isempty(simRunObject.WaveNames)
                        % Copy waveform names from all <m>.<n>.mat files for this simulation run.
                        waveNames = [];
                        simRunName = [database.SimulationResultsNames{resultsObject} ','];
                        for node = 1:fileListLength
                            if startsWith(nodeNames{node},simRunName)
                                % Node name (and <m>.<n>.mat file) belongs to this simulation run.
                                waveformFilePath = [pathname fileNames{node}];
                                if isfile(waveformFilePath)
                                    waveformFile = matfile(waveformFilePath);
                                    if node == 1
                                        % Get waveform names from 1st <m>.<n>.mat file.
                                        waveNames = waveformFile.WaveNames;
                                    else
                                        % Append waveform names from subsequent <m>.<n>.mat file.
                                        count = length(waveNames);
                                        names = waveformFile.WaveNames;
                                        waveNames{count+length(names)} = []; %#ok<AGROW> Pre-allocate additional cells.
                                        for offset = 1:length(names)
                                            waveNames{count+offset} = names{offset};
                                        end
                                    end
                                end
                            end
                        end
                        simRunObject.WaveNames = waveNames; % Save waveform names in SimulationResults object.
                    end
                end
            end
        end
    else
        obj.MixedSignalAnalyzerTool.setStatus('');
        return;
    end
    %database.incrementalFiles = fileNames;
    %database.incrementalNodes = nodeNames;
    % msaHandle.View.Toolstrip.appContainer.Visible=true;
    % pause(4);
    % msaHandle.appContainer.WindowMaximized=true;    
    % msaHandle.appContainer.WindowMinimized=true;
    %fontdata=msaHandle.View.fontData();
    msaHandle.Model.performRequestedUpdates(1,matFilePathTemp,msaMatFileName,database,updateRequest);
    pause(8);
    msaHandle.View.updateTrendCharts(); % Use latest corner tables to create new merged tables and update Trend Charts.
    %msaHandle.View.fontRetrive(fontdata);

    %else
    %msaHandle.Model.readCadenceData(msaMatFileName,matFilePathTemp,updateRequest);
    %end
end
plotDocs=msaHandle.View.PlotDocs;
descriptions{length(plotDocs)} = [];
for i = 1:length(plotDocs)
    descriptions{i} = plotDocs{i}.Title;
end

if(isempty(NameValueArgs.reportFileName))
    %     dateAndTime=datestr(datetime);
    %     dateAndTime=strrep(dateAndTime,'-','_');
    %     dateAndTime=strrep(dateAndTime,':','_');
    %     dateAndTime=strrep(dateAndTime,' ','_');
    %dateAndTime=datestr(now,'yyyymmdd_HHMMSS');
    dateAndTime=char(datetime('now','Format','yyyyMMdd_HHmmss'));
    NameValueArgs.reportFileName=['MSA_Report_',dateAndTime];
end



out=msblks.internal.mixedsignalanalysis.BaseAnalysis.createReport('Type',NameValueArgs.reportType,'FileName',NameValueArgs.reportFileName,'Title',NameValueArgs.reportTitle,...
    'Images',msaHandle.View.PlotFigs,'Description',descriptions,...
    'OutputDir',NameValueArgs.reportPath);

% closingAppContainer property in View.m and appContainer property in
% MixedSignalAnalyzerTool.m is used to close the MSA session.
%if(NameValueArgs.msaVisibility)
%    if (evalin('base','exist(''adeInfo'')'))
%        %allfigs = findall(0,'Type', 'figure');
%        uiwait();
%    end
%else
    msaHandle.appContainer.Visible=false;
    msaHandle.View.ClosingAppContainer=true;
    msaHandle.clearMixedSignalAnalyzer(true);
    delete(msaHandle);
%end
