function includeDirectories = pruneAndCopySupportPackageFiles( requiredFileList, supportPackages, targetDir )
%PRUNEANDCOPYSUPPORTPACKAGEFILES Copies a subset of the listed support
%packages to the target directory
%   There a two different ways a file / directory can be included in the
%   "pruned" supportpack
%       mcc.xml usage: If a support pack has an mcc.mcl file in its
%       registry directory, and that file contains a set of file
%       dependencies, this process will only include files based off of
%       those dependencies 
% 
%       No mcc.xml usage: If there is no mcc.xml file or there is, but it
%       doesn't list any dependencies, the process will include the entire
%       support pack with the exception of registry directory or
%       directieries ending in demo or demos.

    % MatlabFevalRequest didn't seem to be marshaling the objects correctly
    % make sure they represented as cells
    

    includeDirectories = {};
    
    requiredFileList = cell(requiredFileList);
    supportPackages = cell(supportPackages);

    % for changing where the java error reporting is sent
    oldJavaError = java.lang.System.err;
    newJavaError = java.io.PrintStream(java.io.ByteArrayOutputStream());
  
    dependentFileList = [];

    if(~isdir(targetDir))
        % throw an exception if the target directory does not exist
        error(message(...
                    'Compiler:supportpackage:TargetDirNotFound', targetDir));
    end

    % get the list of installed support packages
    pkgInstaller = hwconnectinstaller.PackageInstaller; 
  
    % iterate through the packages and process them accordingly
    pkgCnt = length(supportPackages);
    for pkgItr = 1:pkgCnt
        
        % get the support package info
        pkg = pkgInstaller.getSpPkgInfo(char(supportPackages(pkgItr)));
        
        if(isempty(pkg))
            % the support pack isn't registered
             error(message(...
                    'Compiler:supportpackage:SupportPackageNotRegistered', char(supportPackages(pkgItr))));
        end
        
        if(~isdir(pkg.RootDir))
            % The root dir is missing 
             error(message(...
                    'Compiler:supportpackage:SupportPackageNotFound', pkg.RootDir, char(supportPackages(pkgItr))));
        end
        
        % any other validations we should do on the support pack?
        

        
        % create a subdirectory based off of the support package name
        % newTargetDir = fullfile(targetDir, pkg.Folder);
        newTargetDir = fullfile(targetDir, pkg.Name);
        mkdir (newTargetDir);
        
        fileNodes = [];
        
        % check for the registry/mcc.xml file
        mccxmlFile = fullfile(pkg.RootDir, 'registry', 'mcc.xml');
        % only check the mccXML file if this isn't a MATLAB support pack
        if(~any(strcmp(pkg.BaseProduct, 'MATLAB')) && ~isempty(dir(mccxmlFile)))
            
            % don't want the java aml read errors being printed out
            java.lang.System.setErr(newJavaError);
            
            try
                % check the mcc.xml file has a dependency section
                %   and that there is at least one file listed there
                % read the mcc.xml file
                mccxml = xmlread(mccxmlFile);
                dependencyNode = mccxml.getElementsByTagName('dependency');

                if(dependencyNode.getLength() > 0 )
                    fileNodes = dependencyNode.item(0).getElementsByTagName('file');
                end
            catch
                % bad mcc.xml file
                % set the java error back to the original
                java.lang.System.setErr(oldJavaError);
                
                % raise the error we want to.
                error(message(...
                    'Compiler:supportpackage:CorruptMCCXML', mccxmlFile, char(supportPackages(pkgItr))));
            end
            java.lang.System.setErr(oldJavaError);
        end
        
        % if file dependpencies are listed in the mcc.xml use them to
        % identify the support pack files to include
        if(~isempty(fileNodes) && fileNodes.getLength() > 0)
            % Only call requirements once (if needed at all)
            if(isempty(dependentFileList))
                dependentFileList = dependentFiles(requiredFileList);
            end
                pruneUsingDependencies(pkg.RootDir, newTargetDir, dependentFileList, fileNodes);
                if(~any( strcmp( targetDir, includeDirectories)))
                    includeDirectories = [includeDirectories targetDir];
                end
        else
            % otherwise copy everything 
            
            % g1139736 the directory structure has change with regards to
            % where support packages how installed. The RootDir is no
            % longer the root of the suport package files
            % Construct a new "rootDir" based on the InstallDir and PkgTag
            
            pkgTag = hwconnectinstaller.SupportPackage.getPkgTag(pkg.Name)
            
            newRootDir = fullfile(pkg.InstallDir, pkgTag);
            includeDirectories = [includeDirectories newRootDir];
        end    
    end
    

end

function pruneUsingDependencies(pkgRootDir, newTargetDir, dependentFileList, fileNodes)
    % initialize the return
    
    filesToCopy = {};
    
    % get the count of files
    fileCnt = fileNodes.getLength();
    
    for fileItr=0:fileCnt - 1  % 0 based list
        
        % paths in the mcc.xml files are relative to matlabroot/toolbox
        % they also use the '/' file separator
        nFile = char(fileNodes.item(fileItr).getAttribute('path'));
        nFile = strrep(nFile, '/', filesep);
        filePath = fullfile(matlabroot, 'toolbox', nFile);
        
        %check if the file is in the dependent file list
        if (any (strcmp(filePath, dependentFileList)))
            % if so add the files specified in the data elements for that
            % node to the list of files for copying
            dFileNodes = fileNodes.item(fileItr).getElementsByTagName('data');
            dFileCnt = dFileNodes.getLength();
            for dFileItr = 0:dFileCnt -1
                dFileName = char(dFileNodes.item(dFileItr).getAttribute('name'));
                dFileName = strrep(dFileName, '/', filesep) ;
                
                % don't do the copy here. 
                % add it to the list only if it isn't on it already
                % don't want to copy the same file multiple times
                if(~any( strcmp( dFileName, filesToCopy)))
                    filesToCopy = [filesToCopy dFileName];
                end
            end
            
        end
    end
    
    % if the copiedFiles list is not empty
    % copy the files to the target directory.
    if(~isempty(filesToCopy))

            
            % split the file on the delimiter to get the directory structure
            fileCnt = length(filesToCopy);

            for fileItr=1:fileCnt

                % make sure the directory exists
                fileToCopy = char(filesToCopy(fileItr));
                relativePath =  fileparts(fileToCopy);
                filePath = fullfile(newTargetDir, relativePath);
                if(~isdir(filePath))
                    mkdir(filePath);
                end
                sourceFile = fullfile(pkgRootDir,fileToCopy);
                destFile = fullfile(newTargetDir,fileToCopy);
                try
                    copyfile(sourceFile, destFile);
                catch
                    % ignore copy failures
                end
            end
        
    end
end

function dependentFileList = dependentFiles(requiredFileList)

    warnstatus = warning('OFF', 'MATLAB:dispatcher:pathWarning');
    
    dependentFiles = matlab.depfun.internal.requirements(requiredFileList, 'MCR');
    
    if(~isempty(dependentFiles))
                dependentFileList = {dependentFiles(:).path}; 
            else
                dependentFileList = cellfun(@(x) which(x), vararequiredFileListrgin, 'UniformOutput', false);
    end
    warning(warnstatus);
end
