define(function(require,exports,module){var FileUtils=require("file/FileUtils"),FileSystem=require("filesystem/FileSystem"),FileSystemError=require("filesystem/FileSystemError"),EventDispatcher=require("utils/EventDispatcher"),_=require("thirdparty/lodash"),Async=require("utils/Async"),globmatch=require("thirdparty/globmatch"),PREFERENCE_CHANGE="change",SCOPEORDER_CHANGE="scopeOrderChange";function MemoryStorage(data){this.data=data||{}}function ParsingError(message){this.name="ParsingError",this.message=message||""}function FileStorage(path,createIfMissing,recreateIfInvalid){this.path=path,this.createIfMissing=createIfMissing,this.recreateIfInvalid=recreateIfInvalid,this._lineEndings=FileUtils.getPlatformLineEndings()}function Scope(storage){this.storage=storage,storage.on("changed",this.load.bind(this)),this.data={},this._dirty=!1,this._layers=[],this._layerMap={},this._exclusions=[]}function _findMatchingGlob(pathData,filename){var globs=Object.keys(pathData),globCounter;if(filename)for(globCounter=0;globCounter0&&self.trigger(PREFERENCE_CHANGE,{ids:prefixedIds.map(withoutPrefix)})}),this._listenerInstalled=!0}},on:function(event,preferenceID,handler){var pref;("function"==typeof preferenceID&&(handler=preferenceID,preferenceID=null),preferenceID)?this.getPreference(preferenceID).on(event,handler):(this._installListener(),this._on_internal(event,handler))},off:function(event,preferenceID,handler){var pref;("function"==typeof preferenceID&&(handler=preferenceID,preferenceID=null),preferenceID)?this.getPreference(preferenceID).off(event,handler):this._off_internal(event,handler)},save:function(){return this.base.save()}},_addEventDispatcherImpl(PrefixedPreferencesSystem.prototype),_.extend(PreferencesSystem.prototype,{definePreference:function(id,type,initial,options){if(options=options||{},this._knownPrefs.hasOwnProperty(id))throw new Error("Preference "+id+" was redefined");var pref=this._knownPrefs[id]=new Preference({type:type,initial:initial,name:options.name,description:options.description,validator:options.validator,excludeFromHints:options.excludeFromHints,keys:options.keys,values:options.values,valueType:options.valueType});return this.set(id,initial,{location:{scope:"default"}}),pref},getPreference:function(id){return this._knownPrefs[id]},getAllPreferences:function(){return _.cloneDeep(this._knownPrefs)},_pushToScopeOrder:function(id,before){var defaultScopeOrder=this._defaults.scopeOrder,index=_.findIndex(defaultScopeOrder,function(id){return id===before});if(!(index>-1))throw new Error("Internal error: scope "+before+" should be in the scope order");defaultScopeOrder.splice(index,0,id)},_tryAddToScopeOrder:function(shadowEntry){for(var shadowScopeOrder=this._defaults._shadowScopeOrder,index,i=_.findIndex(shadowScopeOrder,function(entry){return entry===shadowEntry})+1;i-1)shadowEntry=shadowScopeOrder[index];else if(shadowEntry={id:id,promise:promise,scope:scope},addBefore)if((index=_.findIndex(shadowScopeOrder,function(entry){return entry.id===addBefore}))>-1)shadowScopeOrder.splice(index,0,shadowEntry);else{var queue=this._pendingScopes[addBefore];queue||(queue=[],this._pendingScopes[addBefore]=queue),queue.unshift(shadowEntry),isPending=!0}else shadowScopeOrder.unshift(shadowEntry);if(!isPending&&(promise.done(function(){this._scopes[id]=scope,this._tryAddToScopeOrder(shadowEntry)}.bind(this)).fail(function(err){_.pull(shadowScopeOrder,shadowEntry)}.bind(this)),this._pendingScopes[id])){var pending=this._pendingScopes[id];delete this._pendingScopes[id],pending.forEach(function(entry){this._addToScopeOrder(entry.id,entry.scope,entry.promise,id)}.bind(this))}},addToScopeOrder:function(id,addBefore){var shadowScopeOrder=this._defaults._shadowScopeOrder,index=_.findIndex(shadowScopeOrder,function(entry){return entry.id===id}),entry;index>-1&&(entry=shadowScopeOrder[index],this._addToScopeOrder(entry.id,entry.scope,entry.promise,addBefore))},removeFromScopeOrder:function(id){var scope=this._scopes[id];scope&&(_.pull(this._defaults.scopeOrder,id),scope.off(".prefsys"),this.trigger(SCOPEORDER_CHANGE,{id:id,action:"removed"}),this._triggerChange({ids:scope.getKeys()}))},_getContext:function(context){return context?(this.contextBuilder&&(context=this.contextBuilder(context)),context.scopeOrder||(context.scopeOrder=this._defaults.scopeOrder),context):{scopeOrder:this._defaults.scopeOrder}},addScope:function(id,scope,options){var promise;if(options=options||{},this._scopes[id])throw new Error("Attempt to redefine preferences scope: "+id);return scope.get||(scope=new Scope(scope)),promise=scope.load(),this._addToScopeOrder(id,scope,promise,options.before),promise.fail(function(err){err instanceof ParsingError&&console.error(err)}),promise},removeScope:function(id){var scope,shadowIndex;this._scopes[id]&&(this.removeFromScopeOrder(id),shadowIndex=_.findIndex(this._defaults._shadowScopeOrder,function(entry){return entry.id===id}),this._defaults._shadowScopeOrder.splice(shadowIndex,1),delete this._scopes[id])},_getScopeOrder:function(context){return context.scopeOrder||this._defaults.scopeOrder},get:function(id,context){var scopeCounter;context=this._getContext(context);var scopeOrder=this._getScopeOrder(context);for(scopeCounter=0;scopeCounter1))return{valid:!0,stored:!1};location={scope:scopeOrder[scopeOrder.length-2]}}var scope=this._scopes[location.scope];if(!scope)return{valid:!0,stored:!1};var pref=this.getPreference(id),validator=pref&&pref.validator;if(validator&&!validator(value))return{valid:!1,stored:!1};var wasSet=scope.set(id,value,context,location);return wasSet&&(doNotSave||this.save(),this._triggerChange({ids:[id]})),{valid:!0,stored:wasSet}},save:function(){let that=this;if(that._saveInProgress)return that._nextSaveDeferred||(that._nextSaveDeferred=new $.Deferred),that._nextSaveDeferred.promise();var deferred=that._nextSaveDeferred||new $.Deferred;return this._saveInProgress=!0,this._nextSaveDeferred=null,Async.doInParallel(_.values(that._scopes),function(scope){return scope?scope.save():(new $.Deferred).resolve().promise()}).done(function(){that._saveInProgress=!1,that._nextSaveDeferred&&that.save(),deferred.resolve()}).fail(function(err){that._saveInProgress=!1,deferred.reject(err)}),deferred.promise()},signalContextChanged:function(oldContext,newContext){var changes=[];_.each(this._scopes,function(scope){var changedInScope=scope.contextChanged(oldContext,newContext);changedInScope&&changes.push(changedInScope)}),(changes=_.union.apply(null,changes)).length>0&&this._triggerChange({ids:changes})},on:function(event,preferenceID,handler){var pref;("function"==typeof preferenceID&&(handler=preferenceID,preferenceID=null),preferenceID)?this.getPreference(preferenceID).on(event,handler):this._on_internal(event,handler)},off:function(event,preferenceID,handler){var pref;("function"==typeof preferenceID&&(handler=preferenceID,preferenceID=null),preferenceID)?this.getPreference(preferenceID).off(event,handler):this._off_internal(event,handler)},_triggerChange:function(data){this._changeEventQueue?this._changeEventQueue=_.union(this._changeEventQueue,data.ids):this.trigger(PREFERENCE_CHANGE,data)},pauseChangeEvents:function(){this._changeEventQueue||(this._changeEventQueue=[])},resumeChangeEvents:function(){this._changeEventQueue&&(this.trigger(PREFERENCE_CHANGE,{ids:this._changeEventQueue}),this._changeEventQueue=null)},fileChanged:function(filePath){_.forEach(this._scopes,function(scope){scope.fileChanged(filePath)})},getPrefixedSystem:function(prefix){return new PrefixedPreferencesSystem(this,prefix+".")}}),_addEventDispatcherImpl(PreferencesSystem.prototype),exports.PreferencesSystem=PreferencesSystem,exports.Scope=Scope,exports.MemoryStorage=MemoryStorage,exports.PathLayer=PathLayer,exports.ProjectLayer=ProjectLayer,exports.LanguageLayer=LanguageLayer,exports.FileStorage=FileStorage});