<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 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 General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
    
    ***** END LICENSE BLOCK *****
*/

var openURLServerField;
var openURLVersionMenu;
var proxies;
var charsets;
var _io = {};


var Zotero_Preferences = {

	onUnload: function () {
		Zotero_Preferences.Debug_Output.onUnload();
	}
}

function init()
{
	// Display the appropriate modifier keys for the platform
	var rows = document.getElementById('zotero-prefpane-keys').getElementsByTagName('row');
	for (var i=0; i<rows.length; i++) {
		rows[i].firstChild.nextSibling.value = Zotero.isMac ? 'Cmd+Shift+' : 'Ctrl+Alt+';
	}
	
	updateStorageSettings(null, null, true);
	refreshStylesList();
	refreshProxyList();
	populateQuickCopyList();
	updateQuickCopyInstructions();
	initSearchPane();
	Zotero_Preferences.Debug_Output.init();
	
	var charsetMenu = document.getElementById("zotero-import-charsetMenu");
	var charsetMap = Zotero_Charset_Menu.populate(charsetMenu, false);
	charsetMenu.selectedItem =
		charsetMap[Zotero.Prefs.get("import.charset")] ?
			charsetMap[Zotero.Prefs.get("import.charset")] : charsetMap["auto"];
	
	if(window.arguments) {
		_io = window.arguments[0];
		
		if(_io.pane) {
			var pane = document.getElementById(_io.pane);
			document.getElementById('zotero-prefs').showPane(pane);
			// Quick hack to support install prompt from PDF recognize option
			if (_io.action && _io.action == 'pdftools-install') {
				checkPDFToolsDownloadVersion();
			}
		}
	}
}


function onDataDirLoad() {
	var path = document.getElementById('dataDirPath');
	var useDataDir = Zotero.Prefs.get('useDataDir');
	path.setAttribute('disabled', !useDataDir);
}


function onDataDirUpdate(event) {
	var radiogroup = document.getElementById('dataDir');
	var path = document.getElementById('dataDirPath');
	var useDataDir = Zotero.Prefs.get('useDataDir');
	
	// If triggered from the Choose button, don't show the dialog, since
	// Zotero.chooseZoteroDirectory() shows its own
	if (event.originalTarget && event.originalTarget.tagName == 'button') {
		return true;
	}
	// If directory not set or invalid, prompt for location
	if (!getDataDirPath()) {
		event.stopPropagation();
		var file = Zotero.chooseZoteroDirectory(true);
		radiogroup.selectedIndex = file ? 1 : 0;
		return !!file;
	}
	
	var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
		.getService(Components.interfaces.nsIPromptService);
	
	var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
		+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
	var index = ps.confirmEx(window,
		Zotero.getString('general.restartRequired'),
		Zotero.getString('general.restartRequiredForChange'),
		buttonFlags,
		Zotero.getString('general.restartNow'),
		null, null, null, {});
	
	if (index == 0) {
		useDataDir = !!radiogroup.selectedIndex;
		// quit() is asynchronous, but set this here just in case
		Zotero.Prefs.set('useDataDir', useDataDir);
		var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
				.getService(Components.interfaces.nsIAppStartup);
		appStartup.quit(Components.interfaces.nsIAppStartup.eRestart);
		appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
	}
	
	radiogroup.selectedIndex = useDataDir ? 1 : 0;
	return useDataDir;
}


function getDataDirPath() {
	var desc = Zotero.Prefs.get('dataDir');
	if (desc == '') {
		return '';
	}
	
	var file = Components.classes["@mozilla.org/file/local;1"].
		createInstance(Components.interfaces.nsILocalFile);
	try {
		file.persistentDescriptor = desc;
	}
	catch (e) {
		return '';
	}
	return file.path;
}


function populateOpenURLResolvers() {
	var openURLMenu = document.getElementById('openURLMenu');
	
	var openURLResolvers = Zotero.OpenURL.discoverResolvers();
	for each(var r in openURLResolvers) {
		openURLMenu.insertItemAt(i, r.name);
		if (r.url == Zotero.Prefs.get('openURL.resolver') && r.version == Zotero.Prefs.get('openURL.version')) {
			openURLMenu.selectedIndex = i;
		}
	}
	
	var button = document.getElementById('openURLSearchButton');
	switch (openURLResolvers.length) {
		case 0:
			var num = 'zero';
			break;
		case 1:
			var num = 'singular';
			break;
		default:
			var num = 'plural';
	}
	
	button.setAttribute('label', Zotero.getString('zotero.preferences.openurl.resolversFound.' + num, openURLResolvers.length));
}


//
// Sync
//
function updateStorageSettings(enabled, protocol, skipWarnings) {
	if (enabled === null) {
		enabled = document.getElementById('pref-storage-enabled').value;
	}
	
	var oldProtocol = document.getElementById('pref-storage-protocol').value;
	if (protocol === null) {
		protocol = oldProtocol;
	}
	
	var protocolMenu = document.getElementById('storage-protocol');
	var settings = document.getElementById('storage-webdav-settings');
	var sep = document.getElementById('storage-separator');
	
	if (!enabled || protocol == 'zotero') {
		settings.hidden = true;
		sep.hidden = false;
	}
	else {
		settings.hidden = false;
		sep.hidden = true;
	}
	
	protocolMenu.disabled = !enabled;
	
	if (!skipWarnings) {
		// WARN if going between
	}
	
	if (oldProtocol == 'zotero' && protocol == 'webdav') {
		var sql = "SELECT COUNT(*) FROM version WHERE schema='storage_zfs'";
		if (Zotero.DB.valueQuery(sql)) {
			var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
						.getService(Components.interfaces.nsIPrompt);
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
								+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_IS_STRING)
								+ pr.BUTTON_DELAY_ENABLE;
			var account = Zotero.Sync.Server.username;
			var index = pr.confirmEx(
				// TODO: localize
				"Purge Attachment Files on Zotero Servers?",
				
				"If you plan to use WebDAV for file syncing and you previously synced attachment files in My Library "
					+ "to the Zotero servers, you can purge those files from the Zotero servers to give you more "
					+ "storage space for groups.\n\n"
					+ "You can purge files at any time from your account settings on zotero.org.",
				buttonFlags,
				"Purge Files Now",
				"Do Not Purge", null, null, {}
			);
			
			if (index == 0) {
				var sql = "INSERT OR IGNORE INTO settings VALUES (?,?,?)";
				Zotero.DB.query(sql, ['storage', 'zfsPurge', 'user']);
				
				Zotero.Sync.Storage.purgeDeletedStorageFiles('zfs', function (success) {
					if (success) {
						pr.alert(
							Zotero.getString("general.success"),
							"Attachment files from your personal library have been removed from the Zotero servers."
						);
					}
					else {
						pr.alert(
							Zotero.getString("general.error"),
							"An error occurred. Please try again later."
						);
					}
				});
			}
		}
	}
	
	setTimeout(function () {
		updateStorageTerms();
	}, 1)
}


function updateStorageTerms() {
	var terms = document.getElementById('storage-terms');
	
	var libraryEnabled = document.getElementById('pref-storage-enabled').value;
	var storageProtocol = document.getElementById('pref-storage-protocol').value;
	var groupsEnabled = document.getElementById('pref-group-storage-enabled').value;
	
	terms.hidden = !((libraryEnabled && storageProtocol == 'zotero') || groupsEnabled);
}



function unverifyStorageServer() {
	Zotero.Prefs.set('sync.storage.verified', false);
	Zotero.Sync.Storage.resetAllSyncStates(null, true, false);
}

function verifyStorageServer() {
	Zotero.debug("Verifying storage");
	
	var verifyButton = document.getElementById("storage-verify");
	var abortButton = document.getElementById("storage-abort");
	var progressMeter = document.getElementById("storage-progress");
	var urlField = document.getElementById("storage-url");
	var usernameField = document.getElementById("storage-username");
	var passwordField = document.getElementById("storage-password");
	
	var callback = function (uri, status, error) {
		verifyButton.hidden = false;
		abortButton.hidden = true;
		progressMeter.hidden = true;
		
		switch (status) {
			case Zotero.Sync.Storage.ERROR_NO_URL:
				setTimeout(function () {
					urlField.focus();
				}, 1);
				break;
			
			case Zotero.Sync.Storage.ERROR_NO_USERNAME:
				setTimeout(function () {
					usernameField.focus();
				}, 1);
				break;
			
			case Zotero.Sync.Storage.ERROR_NO_PASSWORD:
				setTimeout(function () {
					passwordField.focus();
				}, 1);
				break;
		}
		
		Zotero.Sync.Storage.checkServerCallback(uri, status, window, false, error);
	}
	
	verifyButton.hidden = true;
	abortButton.hidden = false;
	progressMeter.hidden = false;
	var requestHolder = Zotero.Sync.Storage.checkServer('webdav', callback);
	abortButton.onclick = function () {
		if (requestHolder.request) {
			requestHolder.request.onreadystatechange = undefined;
			requestHolder.request.abort();
			verifyButton.hidden = false;
			abortButton.hidden = true;
			progressMeter.hidden = true;
		}
	}
}

function handleSyncResetSelect(obj) {
	var index = obj.selectedIndex;
	var rows = obj.getElementsByTagName('row');
	
	for (var i=0; i<rows.length; i++) {
		if (i == index) {
			rows[i].setAttribute('selected', 'true');
		}
		else {
			rows[i].removeAttribute('selected');
		}
	}
}

function handleSyncReset(action) {
	var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
				.getService(Components.interfaces.nsIPrompt);
	
	if (!Zotero.Sync.Server.enabled) {
		pr.alert(
			Zotero.getString('general.error'),
			// TODO: localize
			"You must enter a username and password in the "
				+ document.getElementById('zotero-prefpane-sync')
					.getElementsByTagName('tab')[0].label
				+ " tab before using the reset options."
		);
		return;
	}
	
	var account = Zotero.Sync.Server.username;
	
	switch (action) {
		case 'restore-from-server':
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
								+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL)
								+ pr.BUTTON_POS_1_DEFAULT;
			var index = pr.confirmEx(
				// TODO: localize
				Zotero.getString('general.warning'),
				"All data in this copy of Zotero will be erased and replaced with "
					+ "data belonging to user '" + account + "' on the Zotero server.",
				buttonFlags,
				"Replace Local Data",
				null, null, null, {}
			);
			
			switch (index) {
				case 0:
					// TODO: better error handling
					
					// Verify username and password
					var callback = function () {
						Zotero.Schema.stopRepositoryTimer();
						Zotero.Sync.Runner.clearSyncTimeout();
						
						Zotero.DB.skipBackup = true;
						
						var file = Zotero.getZoteroDirectory();
						file.append('restore-from-server');
						Zotero.File.putContents(file, '');
						
						var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING);
						var index = pr.confirmEx(
							Zotero.getString('general.restartRequired'),
							// TODO: localize
							"Firefox must be restarted to complete the restore process.",
							buttonFlags,
							Zotero.getString('general.restartNow'),
							null, null, null, {}
						);
						
						var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
								.getService(Components.interfaces.nsIAppStartup);
						appStartup.quit(Components.interfaces.nsIAppStartup.eRestart | Components.interfaces.nsIAppStartup.eAttemptQuit);
					};
					
					// TODO: better way of checking for an active session?
					if (Zotero.Sync.Server.sessionIDComponent == 'sessionid=') {
						Zotero.Sync.Server.login(callback);
					}
					else {
						callback();
					}
					break;
				
				// Cancel
				case 1:
					return;
			}
			break;
		
		case 'restore-to-server':
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
							+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL)
							+ pr.BUTTON_POS_1_DEFAULT;
			var index = pr.confirmEx(
				// TODO: localize
				Zotero.getString('general.warning'),
				"All data belonging to user '" + account + "' on the Zotero server "
					+ "will be erased and replaced with data from this copy of Zotero.",
				buttonFlags,
				"Replace Server Data",
				null, null, null, {}
			);
			
			switch (index) {
				case 0:
					// TODO: better error handling
					Zotero.Sync.Server.clear(function () {
						Zotero.Sync.Server.sync(function () {
							pr.alert(
								"Restore Completed",
								"Data on the Zotero server has been successfully restored."
							);
						});
					});
					break;
				
				// Cancel
				case 1:
					return;
			}
			
			break;
		
		case 'full-sync':
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
							+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL)
							+ pr.BUTTON_POS_1_DEFAULT;
			var index = pr.confirmEx(
				// TODO: localize
				Zotero.getString('general.warning'),
				"The local Zotero library will be completely merged with data belonging to user '" + account + "' on the Zotero server. "
					+ "Any unsynced changes will appear as conflicts.\n\n"
					+ "This option should generally be used only for troubleshooting sync errors.",
				buttonFlags,
				"Sync",
				null, null, null, {}
			);
			
			switch (index) {
				case 0:
					// TODO: better error handling
					Zotero.Sync.Server.resetClient();
					Zotero.Sync.Server.sync(function () {
						pr.alert(
							"Full Sync Completed",
							"The local Zotero library has been merged with data from the Zotero server."
						);
					});
					break;
				
				// Cancel
				case 1:
					return;
			}
			
			break;
		
		case 'reset-storage-history':
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
							+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL)
							+ pr.BUTTON_POS_1_DEFAULT;
			var index = pr.confirmEx(
				// TODO: localize
				Zotero.getString('general.warning'),
				"All file sync history will be cleared.\n\n"
					+ "Any local attachment files that do not exist on the storage server will be uploaded on the next sync.",
				buttonFlags,
				"Reset",
				null, null, null, {}
			);
			
			switch (index) {
				case 0:
					Zotero.Sync.Storage.resetAllSyncStates();<commit_msg>Restore proper feedback for Reset options and add a warning to Restore to Server that there may be a delay before data shows up online<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 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 General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
    
    ***** END LICENSE BLOCK *****
*/

var openURLServerField;
var openURLVersionMenu;
var proxies;
var charsets;
var _io = {};


var Zotero_Preferences = {

	onUnload: function () {
		Zotero_Preferences.Debug_Output.onUnload();
	}
}

function init()
{
	// Display the appropriate modifier keys for the platform
	var rows = document.getElementById('zotero-prefpane-keys').getElementsByTagName('row');
	for (var i=0; i<rows.length; i++) {
		rows[i].firstChild.nextSibling.value = Zotero.isMac ? 'Cmd+Shift+' : 'Ctrl+Alt+';
	}
	
	updateStorageSettings(null, null, true);
	refreshStylesList();
	refreshProxyList();
	populateQuickCopyList();
	updateQuickCopyInstructions();
	initSearchPane();
	Zotero_Preferences.Debug_Output.init();
	
	var charsetMenu = document.getElementById("zotero-import-charsetMenu");
	var charsetMap = Zotero_Charset_Menu.populate(charsetMenu, false);
	charsetMenu.selectedItem =
		charsetMap[Zotero.Prefs.get("import.charset")] ?
			charsetMap[Zotero.Prefs.get("import.charset")] : charsetMap["auto"];
	
	if(window.arguments) {
		_io = window.arguments[0];
		
		if(_io.pane) {
			var pane = document.getElementById(_io.pane);
			document.getElementById('zotero-prefs').showPane(pane);
			// Quick hack to support install prompt from PDF recognize option
			if (_io.action && _io.action == 'pdftools-install') {
				checkPDFToolsDownloadVersion();
			}
		}
	}
}


function onDataDirLoad() {
	var path = document.getElementById('dataDirPath');
	var useDataDir = Zotero.Prefs.get('useDataDir');
	path.setAttribute('disabled', !useDataDir);
}


function onDataDirUpdate(event) {
	var radiogroup = document.getElementById('dataDir');
	var path = document.getElementById('dataDirPath');
	var useDataDir = Zotero.Prefs.get('useDataDir');
	
	// If triggered from the Choose button, don't show the dialog, since
	// Zotero.chooseZoteroDirectory() shows its own
	if (event.originalTarget && event.originalTarget.tagName == 'button') {
		return true;
	}
	// If directory not set or invalid, prompt for location
	if (!getDataDirPath()) {
		event.stopPropagation();
		var file = Zotero.chooseZoteroDirectory(true);
		radiogroup.selectedIndex = file ? 1 : 0;
		return !!file;
	}
	
	var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
		.getService(Components.interfaces.nsIPromptService);
	
	var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
		+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_CANCEL);
	var index = ps.confirmEx(window,
		Zotero.getString('general.restartRequired'),
		Zotero.getString('general.restartRequiredForChange'),
		buttonFlags,
		Zotero.getString('general.restartNow'),
		null, null, null, {});
	
	if (index == 0) {
		useDataDir = !!radiogroup.selectedIndex;
		// quit() is asynchronous, but set this here just in case
		Zotero.Prefs.set('useDataDir', useDataDir);
		var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
				.getService(Components.interfaces.nsIAppStartup);
		appStartup.quit(Components.interfaces.nsIAppStartup.eRestart);
		appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
	}
	
	radiogroup.selectedIndex = useDataDir ? 1 : 0;
	return useDataDir;
}


function getDataDirPath() {
	var desc = Zotero.Prefs.get('dataDir');
	if (desc == '') {
		return '';
	}
	
	var file = Components.classes["@mozilla.org/file/local;1"].
		createInstance(Components.interfaces.nsILocalFile);
	try {
		file.persistentDescriptor = desc;
	}
	catch (e) {
		return '';
	}
	return file.path;
}


function populateOpenURLResolvers() {
	var openURLMenu = document.getElementById('openURLMenu');
	
	var openURLResolvers = Zotero.OpenURL.discoverResolvers();
	for each(var r in openURLResolvers) {
		openURLMenu.insertItemAt(i, r.name);
		if (r.url == Zotero.Prefs.get('openURL.resolver') && r.version == Zotero.Prefs.get('openURL.version')) {
			openURLMenu.selectedIndex = i;
		}
	}
	
	var button = document.getElementById('openURLSearchButton');
	switch (openURLResolvers.length) {
		case 0:
			var num = 'zero';
			break;
		case 1:
			var num = 'singular';
			break;
		default:
			var num = 'plural';
	}
	
	button.setAttribute('label', Zotero.getString('zotero.preferences.openurl.resolversFound.' + num, openURLResolvers.length));
}


//
// Sync
//
function updateStorageSettings(enabled, protocol, skipWarnings) {
	if (enabled === null) {
		enabled = document.getElementById('pref-storage-enabled').value;
	}
	
	var oldProtocol = document.getElementById('pref-storage-protocol').value;
	if (protocol === null) {
		protocol = oldProtocol;
	}
	
	var protocolMenu = document.getElementById('storage-protocol');
	var settings = document.getElementById('storage-webdav-settings');
	var sep = document.getElementById('storage-separator');
	
	if (!enabled || protocol == 'zotero') {
		settings.hidden = true;
		sep.hidden = false;
	}
	else {
		settings.hidden = false;
		sep.hidden = true;
	}
	
	protocolMenu.disabled = !enabled;
	
	if (!skipWarnings) {
		// WARN if going between
	}
	
	if (oldProtocol == 'zotero' && protocol == 'webdav') {
		var sql = "SELECT COUNT(*) FROM version WHERE schema='storage_zfs'";
		if (Zotero.DB.valueQuery(sql)) {
			var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
						.getService(Components.interfaces.nsIPrompt);
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
								+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_IS_STRING)
								+ pr.BUTTON_DELAY_ENABLE;
			var account = Zotero.Sync.Server.username;
			var index = pr.confirmEx(
				// TODO: localize
				"Purge Attachment Files on Zotero Servers?",
				
				"If you plan to use WebDAV for file syncing and you previously synced attachment files in My Library "
					+ "to the Zotero servers, you can purge those files from the Zotero servers to give you more "
					+ "storage space for groups.\n\n"
					+ "You can purge files at any time from your account settings on zotero.org.",
				buttonFlags,
				"Purge Files Now",
				"Do Not Purge", null, null, {}
			);
			
			if (index == 0) {
				var sql = "INSERT OR IGNORE INTO settings VALUES (?,?,?)";
				Zotero.DB.query(sql, ['storage', 'zfsPurge', 'user']);
				
				Zotero.Sync.Storage.purgeDeletedStorageFiles('zfs', function (success) {
					if (success) {
						pr.alert(
							Zotero.getString("general.success"),
							"Attachment files from your personal library have been removed from the Zotero servers."
						);
					}
					else {
						pr.alert(
							Zotero.getString("general.error"),
							"An error occurred. Please try again later."
						);
					}
				});
			}
		}
	}
	
	setTimeout(function () {
		updateStorageTerms();
	}, 1)
}


function updateStorageTerms() {
	var terms = document.getElementById('storage-terms');
	
	var libraryEnabled = document.getElementById('pref-storage-enabled').value;
	var storageProtocol = document.getElementById('pref-storage-protocol').value;
	var groupsEnabled = document.getElementById('pref-group-storage-enabled').value;
	
	terms.hidden = !((libraryEnabled && storageProtocol == 'zotero') || groupsEnabled);
}



function unverifyStorageServer() {
	Zotero.Prefs.set('sync.storage.verified', false);
	Zotero.Sync.Storage.resetAllSyncStates(null, true, false);
}

function verifyStorageServer() {
	Zotero.debug("Verifying storage");
	
	var verifyButton = document.getElementById("storage-verify");
	var abortButton = document.getElementById("storage-abort");
	var progressMeter = document.getElementById("storage-progress");
	var urlField = document.getElementById("storage-url");
	var usernameField = document.getElementById("storage-username");
	var passwordField = document.getElementById("storage-password");
	
	var callback = function (uri, status, error) {
		verifyButton.hidden = false;
		abortButton.hidden = true;
		progressMeter.hidden = true;
		
		switch (status) {
			case Zotero.Sync.Storage.ERROR_NO_URL:
				setTimeout(function () {
					urlField.focus();
				}, 1);
				break;
			
			case Zotero.Sync.Storage.ERROR_NO_USERNAME:
				setTimeout(function () {
					usernameField.focus();
				}, 1);
				break;
			
			case Zotero.Sync.Storage.ERROR_NO_PASSWORD:
				setTimeout(function () {
					passwordField.focus();
				}, 1);
				break;
		}
		
		Zotero.Sync.Storage.checkServerCallback(uri, status, window, false, error);
	}
	
	verifyButton.hidden = true;
	abortButton.hidden = false;
	progressMeter.hidden = false;
	var requestHolder = Zotero.Sync.Storage.checkServer('webdav', callback);
	abortButton.onclick = function () {
		if (requestHolder.request) {
			requestHolder.request.onreadystatechange = undefined;
			requestHolder.request.abort();
			verifyButton.hidden = false;
			abortButton.hidden = true;
			progressMeter.hidden = true;
		}
	}
}

function handleSyncResetSelect(obj) {
	var index = obj.selectedIndex;
	var rows = obj.getElementsByTagName('row');
	
	for (var i=0; i<rows.length; i++) {
		if (i == index) {
			rows[i].setAttribute('selected', 'true');
		}
		else {
			rows[i].removeAttribute('selected');
		}
	}
}

function handleSyncReset(action) {
	var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
				.getService(Components.interfaces.nsIPrompt);
	
	if (!Zotero.Sync.Server.enabled) {
		pr.alert(
			Zotero.getString('general.error'),
			// TODO: localize
			"You must enter a username and password in the "
				+ document.getElementById('zotero-prefpane-sync')
					.getElementsByTagName('tab')[0].label
				+ " tab before using the reset options."
		);
		return;
	}
	
	var account = Zotero.Sync.Server.username;
	
	switch (action) {
		case 'restore-from-server':
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
								+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL)
								+ pr.BUTTON_POS_1_DEFAULT;
			var index = pr.confirmEx(
				// TODO: localize
				Zotero.getString('general.warning'),
				"All data in this copy of Zotero will be erased and replaced with "
					+ "data belonging to user '" + account + "' on the Zotero server.",
				buttonFlags,
				"Replace Local Data",
				null, null, null, {}
			);
			
			switch (index) {
				case 0:
					// TODO: better error handling
					
					// Verify username and password
					var callback = function () {
						Zotero.Schema.stopRepositoryTimer();
						Zotero.Sync.Runner.clearSyncTimeout();
						
						Zotero.DB.skipBackup = true;
						
						var file = Zotero.getZoteroDirectory();
						file.append('restore-from-server');
						Zotero.File.putContents(file, '');
						
						var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING);
						var index = pr.confirmEx(
							Zotero.getString('general.restartRequired'),
							// TODO: localize
							"Firefox must be restarted to complete the restore process.",
							buttonFlags,
							Zotero.getString('general.restartNow'),
							null, null, null, {}
						);
						
						var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"]
								.getService(Components.interfaces.nsIAppStartup);
						appStartup.quit(Components.interfaces.nsIAppStartup.eRestart | Components.interfaces.nsIAppStartup.eAttemptQuit);
					};
					
					// TODO: better way of checking for an active session?
					if (Zotero.Sync.Server.sessionIDComponent == 'sessionid=') {
						Zotero.Sync.Server.login(callback);
					}
					else {
						callback();
					}
					break;
				
				// Cancel
				case 1:
					return;
			}
			break;
		
		case 'restore-to-server':
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
							+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL)
							+ pr.BUTTON_POS_1_DEFAULT;
			var index = pr.confirmEx(
				// TODO: localize
				Zotero.getString('general.warning'),
				"All data belonging to user '" + account + "' on the Zotero server "
					+ "will be erased and replaced with data from this copy of Zotero.\n\n"
					+ "Depending on the size of your library, there may be a delay before "
					+ "your data is available on the server.",
				buttonFlags,
				"Replace Server Data",
				null, null, null, {}
			);
			
			switch (index) {
				case 0:
					// TODO: better error handling
					Zotero.Sync.Server.clear(function () {
						Zotero.Sync.Server.sync({
							onSuccess: function () {
								pr.alert(
									"Restore Completed",
									"Data on the Zotero server has been successfully restored."
								);
							},
							onError: function () {
								// TODO: combine with error dialog for regular syncs
								pr.alert(
									"Restore Failed",
									"An error occurred uploading your data to the server.\n\n"
										+ "Click the sync error icon in the Zotero toolbar "
										+ "for further information."
								);
							}
						});
					});
					break;
				
				// Cancel
				case 1:
					return;
			}
			
			break;
		
		case 'full-sync':
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
							+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL)
							+ pr.BUTTON_POS_1_DEFAULT;
			var index = pr.confirmEx(
				// TODO: localize
				Zotero.getString('general.warning'),
				"The local Zotero library will be completely merged with data belonging to user '" + account + "' on the Zotero server. "
					+ "Any unsynced changes will appear as conflicts.\n\n"
					+ "This option should generally be used only for troubleshooting sync errors.",
				buttonFlags,
				"Sync",
				null, null, null, {}
			);
			
			switch (index) {
				case 0:
					// TODO: better error handling
					Zotero.Sync.Server.resetClient();
					Zotero.Sync.Server.sync({
						onSuccess: function () {
							pr.alert(
								"Full Sync Completed",
								"The local Zotero library has been merged with data from the Zotero server."
							);
						},
						onError: function () {
							// TODO: combine with error dialog for regular syncs
							pr.alert(
								"Full Sync Failed",
								"An error occurred while performing the full sync.\n\n"
									+ "Click the sync error icon in the Zotero toolbar "
									+ "for further information."
							);
						}
					});
					break;
				
				// Cancel
				case 1:
					return;
			}
			
			break;
		
		case 'reset-storage-history':
			var buttonFlags = (pr.BUTTON_POS_0) * (pr.BUTTON_TITLE_IS_STRING)
							+ (pr.BUTTON_POS_1) * (pr.BUTTON_TITLE_CANCEL)
							+ pr.BUTTON_POS_1_DEFAULT;
			var index = pr.confirmEx(
				// TODO: localize
				Zotero.getString('general.warning'),
				"All file sync history will be cleared.\n\n"
					+ "Any local attachment files that do not exist on the storage server will be uploaded on the next sync.",
				buttonFlags,
				"Reset",
				null, null, null, {}
			);
			
			switch (index) {
				case 0:
					Zotero.Sync.Storage.resetAllSyncStates();
{'fraction_non_alphanumeric': 0.12350794120548486, 'fraction_numerical': 0.0033540495215547005, 'mean_word_length': 3.299123551031948, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4619514', 'n_tokens_mistral': 11743, 'n_tokens_neox': 9584, 'n_words': 2265}