export default class IsolatedFileSystemManager extends Common.Object{constructor(){super();this._fileSystems=new Map();this._callbacks=new Map();this._progresses=new Map();Host.InspectorFrontendHost.events.addEventListener(Host.InspectorFrontendHostAPI.Events.FileSystemRemoved,this._onFileSystemRemoved,this);Host.InspectorFrontendHost.events.addEventListener(Host.InspectorFrontendHostAPI.Events.FileSystemAdded,this._onFileSystemAdded,this);Host.InspectorFrontendHost.events.addEventListener(Host.InspectorFrontendHostAPI.Events.FileSystemFilesChangedAddedRemoved,this._onFileSystemFilesChanged,this);Host.InspectorFrontendHost.events.addEventListener(Host.InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated,this._onIndexingTotalWorkCalculated,this);Host.InspectorFrontendHost.events.addEventListener(Host.InspectorFrontendHostAPI.Events.IndexingWorked,this._onIndexingWorked,this);Host.InspectorFrontendHost.events.addEventListener(Host.InspectorFrontendHostAPI.Events.IndexingDone,this._onIndexingDone,this);Host.InspectorFrontendHost.events.addEventListener(Host.InspectorFrontendHostAPI.Events.SearchCompleted,this._onSearchCompleted,this);this._initExcludePatterSetting();this._fileSystemRequestResolve=null;this._fileSystemsLoadedPromise=this._requestFileSystems();}
_requestFileSystems(){let fulfill;const promise=new Promise(f=>fulfill=f);Host.InspectorFrontendHost.events.addEventListener(Host.InspectorFrontendHostAPI.Events.FileSystemsLoaded,onFileSystemsLoaded,this);Host.InspectorFrontendHost.requestFileSystems();return promise;function onFileSystemsLoaded(event){const fileSystems=(event.data);const promises=[];for(let i=0;i<fileSystems.length;++i){promises.push(this._innerAddFileSystem(fileSystems[i],false));}
Promise.all(promises).then(onFileSystemsAdded);}
function onFileSystemsAdded(fileSystems){fulfill(fileSystems.filter(fs=>!!fs));}}
addFileSystem(type){return new Promise(resolve=>{this._fileSystemRequestResolve=resolve;Host.InspectorFrontendHost.addFileSystem(type||'');});}
removeFileSystem(fileSystem){Host.InspectorFrontendHost.removeFileSystem(fileSystem.embedderPath());}
waitForFileSystems(){return this._fileSystemsLoadedPromise;}
_innerAddFileSystem(fileSystem,dispatchEvent){const embedderPath=fileSystem.fileSystemPath;const fileSystemURL=Common.ParsedURL.platformPathToURL(fileSystem.fileSystemPath);const promise=Persistence.IsolatedFileSystem.create(this,fileSystemURL,embedderPath,fileSystem.type,fileSystem.fileSystemName,fileSystem.rootURL);return promise.then(storeFileSystem.bind(this));function storeFileSystem(fileSystem){if(!fileSystem){return null;}
this._fileSystems.set(fileSystemURL,fileSystem);if(dispatchEvent){this.dispatchEventToListeners(Events.FileSystemAdded,fileSystem);}
return fileSystem;}}
addPlatformFileSystem(fileSystemURL,fileSystem){this._fileSystems.set(fileSystemURL,fileSystem);this.dispatchEventToListeners(Events.FileSystemAdded,fileSystem);}
async _onFileSystemAdded(event){const errorMessage=(event.data['errorMessage']);let fileSystem=(event.data['fileSystem']);if(errorMessage){Common.console.error(Common.UIString('Unable to add filesystem: %s',errorMessage));if(!this._fileSystemRequestResolve){return;}
this._fileSystemRequestResolve.call(null,null);this._fileSystemRequestResolve=null;}else if(fileSystem){fileSystem=await this._innerAddFileSystem(fileSystem,true);if(this._fileSystemRequestResolve){this._fileSystemRequestResolve.call(null,fileSystem);this._fileSystemRequestResolve=null;}}}
_onFileSystemRemoved(event){const embedderPath=(event.data);const fileSystemPath=Common.ParsedURL.platformPathToURL(embedderPath);const isolatedFileSystem=this._fileSystems.get(fileSystemPath);if(!isolatedFileSystem){return;}
this._fileSystems.delete(fileSystemPath);isolatedFileSystem.fileSystemRemoved();this.dispatchEventToListeners(Events.FileSystemRemoved,isolatedFileSystem);}
_onFileSystemFilesChanged(event){const urlPaths={changed:groupFilePathsIntoFileSystemPaths.call(this,event.data.changed),added:groupFilePathsIntoFileSystemPaths.call(this,event.data.added),removed:groupFilePathsIntoFileSystemPaths.call(this,event.data.removed)};this.dispatchEventToListeners(Events.FileSystemFilesChanged,urlPaths);function groupFilePathsIntoFileSystemPaths(embedderPaths){const paths=new Platform.Multimap();for(const embedderPath of embedderPaths){const filePath=Common.ParsedURL.platformPathToURL(embedderPath);for(const fileSystemPath of this._fileSystems.keys()){if(this._fileSystems.get(fileSystemPath).isFileExcluded(embedderPath)){continue;}
const pathPrefix=fileSystemPath.endsWith('/')?fileSystemPath:fileSystemPath+'/';if(!filePath.startsWith(pathPrefix)){continue;}
paths.set(fileSystemPath,filePath);}}
return paths;}}
fileSystems(){return this._fileSystems.valuesArray();}
fileSystem(fileSystemPath){return this._fileSystems.get(fileSystemPath)||null;}
_initExcludePatterSetting(){const defaultCommonExcludedFolders=['/node_modules/','/bower_components/','/\\.devtools','/\\.git/','/\\.sass-cache/','/\\.hg/','/\\.idea/','/\\.svn/','/\\.cache/','/\\.project/'];const defaultWinExcludedFolders=['/Thumbs.db$','/ehthumbs.db$','/Desktop.ini$','/\\$RECYCLE.BIN/'];const defaultMacExcludedFolders=['/\\.DS_Store$','/\\.Trashes$','/\\.Spotlight-V100$','/\\.AppleDouble$','/\\.LSOverride$','/Icon$','/\\._.*$'];const defaultLinuxExcludedFolders=['/.*~$'];let defaultExcludedFolders=defaultCommonExcludedFolders;if(Host.isWin()){defaultExcludedFolders=defaultExcludedFolders.concat(defaultWinExcludedFolders);}else if(Host.isMac()){defaultExcludedFolders=defaultExcludedFolders.concat(defaultMacExcludedFolders);}else{defaultExcludedFolders=defaultExcludedFolders.concat(defaultLinuxExcludedFolders);}
const defaultExcludedFoldersPattern=defaultExcludedFolders.join('|');this._workspaceFolderExcludePatternSetting=Common.settings.createRegExpSetting('workspaceFolderExcludePattern',defaultExcludedFoldersPattern,Host.isWin()?'i':'');}
workspaceFolderExcludePatternSetting(){return this._workspaceFolderExcludePatternSetting;}
registerCallback(callback){const requestId=++_lastRequestId;this._callbacks.set(requestId,callback);return requestId;}
registerProgress(progress){const requestId=++_lastRequestId;this._progresses.set(requestId,progress);return requestId;}
_onIndexingTotalWorkCalculated(event){const requestId=(event.data['requestId']);const totalWork=(event.data['totalWork']);const progress=this._progresses.get(requestId);if(!progress){return;}
progress.setTotalWork(totalWork);}
_onIndexingWorked(event){const requestId=(event.data['requestId']);const worked=(event.data['worked']);const progress=this._progresses.get(requestId);if(!progress){return;}
progress.worked(worked);if(progress.isCanceled()){Host.InspectorFrontendHost.stopIndexing(requestId);this._onIndexingDone(event);}}
_onIndexingDone(event){const requestId=(event.data['requestId']);const progress=this._progresses.get(requestId);if(!progress){return;}
progress.done();this._progresses.delete(requestId);}
_onSearchCompleted(event){const requestId=(event.data['requestId']);const files=(event.data['files']);const callback=this._callbacks.get(requestId);if(!callback){return;}
callback.call(null,files);this._callbacks.delete(requestId);}}
export const Events={FileSystemAdded:Symbol('FileSystemAdded'),FileSystemRemoved:Symbol('FileSystemRemoved'),FileSystemFilesChanged:Symbol('FileSystemFilesChanged'),ExcludedFolderAdded:Symbol('ExcludedFolderAdded'),ExcludedFolderRemoved:Symbol('ExcludedFolderRemoved')};let _lastRequestId=0;self.Persistence=self.Persistence||{};Persistence=Persistence||{};Persistence.IsolatedFileSystemManager=IsolatedFileSystemManager;Persistence.IsolatedFileSystemManager.Events=Events;Persistence.IsolatedFileSystemManager.FileSystem;Persistence.IsolatedFileSystemManager.FilesChangedData;Persistence.isolatedFileSystemManager;