<commit_before>/*
    ***** BEGIN LICENSE BLOCK *****
    
    Copyright © 2009 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org
    
    This file is part of Zotero.
    
    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.
    
    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
    
    ***** END LICENSE BLOCK *****
*/

Zotero.Libraries = new function () {
	let _userLibraryID;
	Zotero.defineProperty(this, 'userLibraryID', {
		get: function() { 
			if (_userLibraryID === undefined) {
				throw new Error("Library data not yet loaded");
			}
			return _userLibraryID;
		}
	});
	
	let _userLibrary;
	Zotero.defineProperty(this, 'userLibrary', {
		get: function () {
			return _userLibrary || (_userLibrary = Zotero.Libraries.get(this.userLibraryID));
		}
	})
	
	let _publicationsLibraryID;
	Zotero.defineProperty(this, 'publicationsLibraryID', {
		get: function() {
			if (_publicationsLibraryID === undefined) {
				throw new Error("Library data not yet loaded");
			}
			return _publicationsLibraryID;
		}
	});
	
	/**
	 * Manage cache
	 */
	this._cache = null;
	
	this._makeCache = function() {
		return {};
	}
	
	this.register = function(library) {
		if (!this._cache) throw new Error("Zotero.Libraries cache is not initialized");
		Zotero.debug("Zotero.Libraries: Registering library " + library.libraryID, 5);
		this._addToCache(this._cache, library);
	};
	
	this._addToCache = function(cache, library) {
		if (!library.libraryID) throw new Error("Cannot register an unsaved library");
		cache[library.libraryID] = library;
	}
	
	this.unregister = function(libraryID) {
		if (!this._cache) throw new Error("Zotero.Libraries cache is not initialized");
		Zotero.debug("Zotero.Libraries: Unregistering library " + libraryID, 5);
		delete this._cache[libraryID];
	};
	
	/**
	 * Loads all libraries from DB. Groups, Feeds, etc. should not maintain an
	 * independent cache.
	 */
	this.init = Zotero.Promise.coroutine(function* () {
		let specialLoading = ['feed', 'group'];
		
		// Invalidate caches until we're done loading everything
		let libTypes = ['library'].concat(specialLoading);
		let newCaches = {};
		for (let i=0; i<libTypes.length; i++) {
			let objs = Zotero.DataObjectUtilities.getObjectsClassForObjectType(libTypes[i]);
			delete objs._cache;
			
			newCaches[libTypes[i]] = objs._makeCache();
		}
		
		let sql = Zotero.Library._rowSQL
			// Exclude libraries that require special loading
			+ " WHERE type NOT IN "
			+ "(" + Array(specialLoading.length).fill('?').join(',') + ")";
		let rows = yield Zotero.DB.queryAsync(sql, specialLoading);
		
		for (let i=0; i<rows.length; i++) {
			let row = rows[i];
			
			let library;
			switch (row._libraryType) {
				case 'user':
				case 'publications':
					library = new Zotero.Library();
					library._loadDataFromRow(row); // Does not call save()
					break;
				default:
					throw new Error('Unhandled library type "' + row._libraryType + '"');
			}
			
			if (library.libraryType == 'user') {
				_userLibraryID = library.libraryID;
			}
			else if (library.libraryType == 'publications') {
				_publicationsLibraryID = library.libraryID;
			}
			
			this._addToCache(newCaches.library, library);
		}
		
		// Load other libraries
		for (let i=0; i<specialLoading.length; i++) {
			let libType = specialLoading[i];
			let LibType = Zotero.Utilities.capitalize(libType);
			
			let libs = yield Zotero.DB.queryAsync(Zotero[LibType]._rowSQL);
			for (let j=0; j<libs.length; j++) {
				let lib = new Zotero[LibType]();
				lib._loadDataFromRow(libs[j]);
				
				this._addToCache(newCaches.library, lib);
				Zotero[lib._ObjectTypePlural]._addToCache(newCaches[libType], lib);
			}
		}
		
		// Set new caches
		for (let libType in newCaches) {
			Zotero.DataObjectUtilities.getObjectsClassForObjectType(libType)
				._cache = newCaches[libType];
		}
	});
	
	/**
	 * @param {Integer} libraryID
	 * @return {Boolean}
	 */
	this.exists = function(libraryID) {
		if (!this._cache) throw new Error("Zotero.Libraries cache is not initialized");
		return this._cache[libraryID] !== undefined;
	}
	
	
	this._ensureExists = function(libraryID) {
		if (!this.exists(libraryID)) {
			throw new Error("Invalid library ID " + libraryID);
		}
	}
	
	
	/**
	 * @return {Integer[]} - All library IDs
	 */
	this.getAll = function () {
		if (!this._cache) throw new Error("Zotero.Libraries cache is not initialized");
		return Object.keys(this._cache).map(v => parseInt(v));
	}
	
	
	/**
	 * Get an existing library
	 *
	 * @param {Integer} libraryID
	 * @return {Zotero.Library[] | Zotero.Library}
	 */
	this.get = function(libraryID) {
		return this._cache[libraryID] || false;
	}
	
	
	/**
	 * @deprecated
	 */
	this.getName = function (libraryID) {
		Zotero.debug("Zotero.Libraries.getName() is deprecated. Use Zotero.Library.prototype.name instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).name;
	}
	
	
	/**
	 * @deprecated
	 */
	this.getType = function (libraryID) {
		Zotero.debug("Zotero.Libraries.getType() is deprecated. Use Zotero.Library.prototype.libraryType instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).libraryType;
	}
	
	
	/**
	 * @deprecated
	 * 
	 * @param {Integer} libraryID
	 * @return {Integer}
	 */
	this.getVersion = function (libraryID) {
		Zotero.debug("Zotero.Libraries.getVersion() is deprecated. Use Zotero.Library.prototype.libraryVersion instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).libraryVersion;
	}
	
	
	/**
	 * @deprecated
	 *
	 * @param {Integer} libraryID
	 * @param {Integer} version
	 * @return {Promise}
	 */
	this.setVersion = Zotero.Promise.method(function(libraryID, version) {
		Zotero.debug("Zotero.Libraries.setVersion() is deprecated. Use Zotero.Library.prototype.libraryVersion instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.libraryVersion = version;
		return library.saveTx();
	});
	
	/**
	 * @deprecated
	 */
	this.getLastSyncTime = function (libraryID) {
		Zotero.debug("Zotero.Libraries.getLastSyncTime() is deprecated. Use Zotero.Library.prototype.lastSync instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).lastSync;
	};
	
	
	/**
	 * @deprecated
	 * 
	 * @param {Integer} libraryID
	 * @param {Date} lastSyncTime
	 * @return {Promise}
	 */
	this.setLastSyncTime = Zotero.Promise.method(function (libraryID, lastSyncTime) {
		Zotero.debug("Zotero.Libraries.setLastSyncTime() is deprecated. Use Zotero.Library.prototype.lastSync instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.lastSync = lastSyncTime;
		return library.saveTx();
	});
	
	/**
	 * @deprecated
	 */
	this.isEditable = function (libraryID) {
		Zotero.debug("Zotero.Libraries.isEditable() is deprecated. Use Zotero.Library.prototype.editable instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).editable;
	}
	
	/**
	 * @deprecated
	 *
	 * @return {Promise}
	 */
	this.setEditable = Zotero.Promise.method(function(libraryID, editable) {
		Zotero.debug("Zotero.Libraries.setEditable() is deprecated. Use Zotero.Library.prototype.editable instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.editable = editable;
		return library.saveTx();
	});
	
	/**
	 * @deprecated
	 */
	this.isFilesEditable = function (libraryID) {
		Zotero.debug("Zotero.Libraries.isFilesEditable() is deprecated. Use Zotero.Library.prototype.filesEditable instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).filesEditable;
	};
	
	/**
	 * @deprecated
	 * 
	 * @return {Promise}
	 */
	this.setFilesEditable = Zotero.Promise.coroutine(function* (libraryID, filesEditable) {
		Zotero.debug("Zotero.Libraries.setFilesEditable() is deprecated. Use Zotero.Library.prototype.filesEditable instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.filesEditable = filesEditable;
		return library.saveTx();
	});
	
	/**
	 * @deprecated
	 */
	this.isGroupLibrary = function (libraryID) {
		Zotero.debug("Zotero.Libraries.isGroupLibrary() is deprecated. Use Zotero.Library.prototype.isGroup instead");
		this._ensureExists(libraryID);
		return !!Zotero.Libraries.get(libraryID).isGroup;
	}
	
	/**
	 * @deprecated
	 */
	this.hasTrash = function (libraryID) {
		Zotero.debug("Zotero.Libraries.hasTrash() is deprecated. Use Zotero.Library.prototype.hasTrash instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).hasTrash;
	}
	
	/**
	 * @deprecated
	 */
	this.updateLastSyncTime = Zotero.Promise.method(function(libraryID) {
		Zotero.debug("Zotero.Libraries.updateLastSyncTime() is deprecated. Use Zotero.Library.prototype.updateLastSyncTime instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.updateLastSyncTime();
		return library.saveTx()
			.return();
	})
}<commit_msg>Make sure Zotero.Libraries.userLibrary doesn't get out of sync<commit_after>/*
    ***** BEGIN LICENSE BLOCK *****
    
    Copyright © 2009 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org
    
    This file is part of Zotero.
    
    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.
    
    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
    
    ***** END LICENSE BLOCK *****
*/

Zotero.Libraries = new function () {
	let _userLibraryID;
	Zotero.defineProperty(this, 'userLibraryID', {
		get: function() { 
			if (_userLibraryID === undefined) {
				throw new Error("Library data not yet loaded");
			}
			return _userLibraryID;
		}
	});
	
	Zotero.defineProperty(this, 'userLibrary', {
		get: function () {
			return Zotero.Libraries.get(_userLibraryID);
		}
	})
	
	let _publicationsLibraryID;
	Zotero.defineProperty(this, 'publicationsLibraryID', {
		get: function() {
			if (_publicationsLibraryID === undefined) {
				throw new Error("Library data not yet loaded");
			}
			return _publicationsLibraryID;
		}
	});
	
	/**
	 * Manage cache
	 */
	this._cache = null;
	
	this._makeCache = function() {
		return {};
	}
	
	this.register = function(library) {
		if (!this._cache) throw new Error("Zotero.Libraries cache is not initialized");
		Zotero.debug("Zotero.Libraries: Registering library " + library.libraryID, 5);
		this._addToCache(this._cache, library);
	};
	
	this._addToCache = function(cache, library) {
		if (!library.libraryID) throw new Error("Cannot register an unsaved library");
		cache[library.libraryID] = library;
	}
	
	this.unregister = function(libraryID) {
		if (!this._cache) throw new Error("Zotero.Libraries cache is not initialized");
		Zotero.debug("Zotero.Libraries: Unregistering library " + libraryID, 5);
		delete this._cache[libraryID];
	};
	
	/**
	 * Loads all libraries from DB. Groups, Feeds, etc. should not maintain an
	 * independent cache.
	 */
	this.init = Zotero.Promise.coroutine(function* () {
		let specialLoading = ['feed', 'group'];
		
		// Invalidate caches until we're done loading everything
		let libTypes = ['library'].concat(specialLoading);
		let newCaches = {};
		for (let i=0; i<libTypes.length; i++) {
			let objs = Zotero.DataObjectUtilities.getObjectsClassForObjectType(libTypes[i]);
			delete objs._cache;
			
			newCaches[libTypes[i]] = objs._makeCache();
		}
		
		let sql = Zotero.Library._rowSQL
			// Exclude libraries that require special loading
			+ " WHERE type NOT IN "
			+ "(" + Array(specialLoading.length).fill('?').join(',') + ")";
		let rows = yield Zotero.DB.queryAsync(sql, specialLoading);
		
		for (let i=0; i<rows.length; i++) {
			let row = rows[i];
			
			let library;
			switch (row._libraryType) {
				case 'user':
				case 'publications':
					library = new Zotero.Library();
					library._loadDataFromRow(row); // Does not call save()
					break;
				default:
					throw new Error('Unhandled library type "' + row._libraryType + '"');
			}
			
			if (library.libraryType == 'user') {
				_userLibraryID = library.libraryID;
			}
			else if (library.libraryType == 'publications') {
				_publicationsLibraryID = library.libraryID;
			}
			
			this._addToCache(newCaches.library, library);
		}
		
		// Load other libraries
		for (let i=0; i<specialLoading.length; i++) {
			let libType = specialLoading[i];
			let LibType = Zotero.Utilities.capitalize(libType);
			
			let libs = yield Zotero.DB.queryAsync(Zotero[LibType]._rowSQL);
			for (let j=0; j<libs.length; j++) {
				let lib = new Zotero[LibType]();
				lib._loadDataFromRow(libs[j]);
				
				this._addToCache(newCaches.library, lib);
				Zotero[lib._ObjectTypePlural]._addToCache(newCaches[libType], lib);
			}
		}
		
		// Set new caches
		for (let libType in newCaches) {
			Zotero.DataObjectUtilities.getObjectsClassForObjectType(libType)
				._cache = newCaches[libType];
		}
	});
	
	/**
	 * @param {Integer} libraryID
	 * @return {Boolean}
	 */
	this.exists = function(libraryID) {
		if (!this._cache) throw new Error("Zotero.Libraries cache is not initialized");
		return this._cache[libraryID] !== undefined;
	}
	
	
	this._ensureExists = function(libraryID) {
		if (!this.exists(libraryID)) {
			throw new Error("Invalid library ID " + libraryID);
		}
	}
	
	
	/**
	 * @return {Integer[]} - All library IDs
	 */
	this.getAll = function () {
		if (!this._cache) throw new Error("Zotero.Libraries cache is not initialized");
		return Object.keys(this._cache).map(v => parseInt(v));
	}
	
	
	/**
	 * Get an existing library
	 *
	 * @param {Integer} libraryID
	 * @return {Zotero.Library[] | Zotero.Library}
	 */
	this.get = function(libraryID) {
		return this._cache[libraryID] || false;
	}
	
	
	/**
	 * @deprecated
	 */
	this.getName = function (libraryID) {
		Zotero.debug("Zotero.Libraries.getName() is deprecated. Use Zotero.Library.prototype.name instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).name;
	}
	
	
	/**
	 * @deprecated
	 */
	this.getType = function (libraryID) {
		Zotero.debug("Zotero.Libraries.getType() is deprecated. Use Zotero.Library.prototype.libraryType instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).libraryType;
	}
	
	
	/**
	 * @deprecated
	 * 
	 * @param {Integer} libraryID
	 * @return {Integer}
	 */
	this.getVersion = function (libraryID) {
		Zotero.debug("Zotero.Libraries.getVersion() is deprecated. Use Zotero.Library.prototype.libraryVersion instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).libraryVersion;
	}
	
	
	/**
	 * @deprecated
	 *
	 * @param {Integer} libraryID
	 * @param {Integer} version
	 * @return {Promise}
	 */
	this.setVersion = Zotero.Promise.method(function(libraryID, version) {
		Zotero.debug("Zotero.Libraries.setVersion() is deprecated. Use Zotero.Library.prototype.libraryVersion instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.libraryVersion = version;
		return library.saveTx();
	});
	
	/**
	 * @deprecated
	 */
	this.getLastSyncTime = function (libraryID) {
		Zotero.debug("Zotero.Libraries.getLastSyncTime() is deprecated. Use Zotero.Library.prototype.lastSync instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).lastSync;
	};
	
	
	/**
	 * @deprecated
	 * 
	 * @param {Integer} libraryID
	 * @param {Date} lastSyncTime
	 * @return {Promise}
	 */
	this.setLastSyncTime = Zotero.Promise.method(function (libraryID, lastSyncTime) {
		Zotero.debug("Zotero.Libraries.setLastSyncTime() is deprecated. Use Zotero.Library.prototype.lastSync instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.lastSync = lastSyncTime;
		return library.saveTx();
	});
	
	/**
	 * @deprecated
	 */
	this.isEditable = function (libraryID) {
		Zotero.debug("Zotero.Libraries.isEditable() is deprecated. Use Zotero.Library.prototype.editable instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).editable;
	}
	
	/**
	 * @deprecated
	 *
	 * @return {Promise}
	 */
	this.setEditable = Zotero.Promise.method(function(libraryID, editable) {
		Zotero.debug("Zotero.Libraries.setEditable() is deprecated. Use Zotero.Library.prototype.editable instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.editable = editable;
		return library.saveTx();
	});
	
	/**
	 * @deprecated
	 */
	this.isFilesEditable = function (libraryID) {
		Zotero.debug("Zotero.Libraries.isFilesEditable() is deprecated. Use Zotero.Library.prototype.filesEditable instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).filesEditable;
	};
	
	/**
	 * @deprecated
	 * 
	 * @return {Promise}
	 */
	this.setFilesEditable = Zotero.Promise.coroutine(function* (libraryID, filesEditable) {
		Zotero.debug("Zotero.Libraries.setFilesEditable() is deprecated. Use Zotero.Library.prototype.filesEditable instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.filesEditable = filesEditable;
		return library.saveTx();
	});
	
	/**
	 * @deprecated
	 */
	this.isGroupLibrary = function (libraryID) {
		Zotero.debug("Zotero.Libraries.isGroupLibrary() is deprecated. Use Zotero.Library.prototype.isGroup instead");
		this._ensureExists(libraryID);
		return !!Zotero.Libraries.get(libraryID).isGroup;
	}
	
	/**
	 * @deprecated
	 */
	this.hasTrash = function (libraryID) {
		Zotero.debug("Zotero.Libraries.hasTrash() is deprecated. Use Zotero.Library.prototype.hasTrash instead");
		this._ensureExists(libraryID);
		return Zotero.Libraries.get(libraryID).hasTrash;
	}
	
	/**
	 * @deprecated
	 */
	this.updateLastSyncTime = Zotero.Promise.method(function(libraryID) {
		Zotero.debug("Zotero.Libraries.updateLastSyncTime() is deprecated. Use Zotero.Library.prototype.updateLastSyncTime instead");
		this._ensureExists(libraryID);
		
		let library = Zotero.Libraries.get(libraryID);
		library.updateLastSyncTime();
		return library.saveTx()
			.return();
	})
}
{'fraction_non_alphanumeric': 0.1311985076946992, 'fraction_numerical': 0.0011399554381056013, 'mean_word_length': 3.793840039741679, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4220293', 'n_tokens_mistral': 6881, 'n_tokens_neox': 6122, 'n_words': 1339}