MRLookup

Extract BibTeX data automatically and modify BibTeX Key to AUTHOR_YEAR_TITLE.

// ==UserScript==
// @name              MRLookup
// @namespace         vanabeljs
// @description       Extract BibTeX data automatically and modify BibTeX Key to AUTHOR_YEAR_TITLE.
// @description:ZH-CN 自动提取BibTeX数据并修改BibTeX关键字为AUTHOR_YEAR_TITLE的形式.
// @author            Van Abel
// @copyright         2018, Van Abel (https://home.vanabel.cn)
// @license           OSI-SPDX-Short-Identifier
// @version           3.0.5
// @include           */mathscinet/search/publications.html?fmt=bibtex*
// @include           */mathscinet/clipboard.html
// @include           */mrlookup
// @include           https://mathscinet.ams.org/*
// @exclude           https://github.com/*
// @exclude           https://*.github.com/*
// @exclude           https://*.github.io/*
// @grant            GM_setValue
// @grant            GM_getValue
// @grant            GM_registerMenuCommand
// @grant            GM_setClipboard
// ==/UserScript==

// ==OpenUserJS==
// @author Van Abel
// ==/OpenUserJS==

/**
 * Webhook test: Testing automatic sync to Greasy Fork
 */

/*The first word to ignore in title*/
var IgnoreStringInTitle = [
	'a',
	'an',
	'on',
	'the',
	'another'
];
function IgnoreStringToRegExp(arr) {
	var regexp = '^(';
	var arrlen = arr.length;
	for (var i = 0; i < arrlen; i++) {
		if (i == arrlen - 1) {
			regexp += '(' + arr[i] + ')';
		} else {
			regexp += '(' + arr[i] + ')|';
		}
	}
	regexp += ')\\s+';
	return regexp;
}//console.log(IgnoreStringToRegExp(IgnoreStringInTitle));
/*split bibdata*/

function parseBibTexLine(text) {
	try {
		var m = text.match(/^\s*(\S+)\s*=\s*/);
		if (!m) {
			console.error('Invalid line format:', text);
			return null;
		}
		var name = m[1];
		var search = text.slice(m[0].length);
		var re = /[\n\r,{}]/g;
		var braceCount = 0;
		var length = m[0].length;
		do {
			m = re.exec(search);
			if (!m) break;
			if (m[0] === '{') {
				braceCount++;
			} else if (m[0] === '}') {
				if (braceCount === 0) {
					throw new Error('Unexpected closing brace: "}"');
				}
				braceCount--;
			}
		} while (braceCount > 0);
		return {
			field: name,
			value: search.slice(0, re.lastIndex),
			length: length + re.lastIndex + (m ? m[0].length : 0)
		};
	} catch (error) {
		console.error('Error parsing BibTeX line:', error);
		return null;
	}
}
function parseBibTex(text) {
	var m = text.match(/^\s*@([^{]+){([^,\n]+)[,\n]/);
	if (!m) {
		throw new Error('Unrecogonised header format');
	}
	var result = {
		typeName: m[1].trim(),
		citationKey: m[2].trim()
	};
	text = text.slice(m[0].length).trim();
	while (text[0] !== '}') {
		var pair = parseBibTexLine(text);
		if (!pair) break;
		// Convert field name to lowercase for consistency
		result[pair.field.toLowerCase()] = pair.value;
		text = text.slice(pair.length).trim();
	}
	return result;
}

function cleanAuthorName(author) {
	if (!author) return '';
	
	// 分割多个作者
	let authors = author.split(/\s*and\s*/);
	// 获取所有作者的姓
	let lastNames = authors.map(author => {
		// 提取姓(通常是逗号前的部分)
		let lastName = author.split(',')[0];
		// 对于复合姓氏,取最后一部分
		let nameParts = lastName.split(/\s+/);
		let finalLastName = nameParts[nameParts.length - 1];
		// 清理特殊字符
		return finalLastName.replace(/[{}\\\s\'"`]/g, '');
	});
	// 拼接所有作者的姓
	return lastNames.join('');
}

function cleanTitle(title) {
	if (!title) return '';
	
	// 移除LaTeX命令和数学符号
	title = title.replace(/\\[a-zA-Z]+/g, '')          // 移除LaTeX命令
		  .replace(/\$[^$]*\$/g, '')                   // 移除数学公式
		  .replace(/[{}\\\'"`]/g, '')                  // 移除特殊字符
		  .replace(/\{[^}]*\}/g, '');                  // 移除花括号内容
	
	// 按空格、连字符和标点符号分割成单词
	let words = title.split(/[\s\-,.:;]+/)
		.filter(word => word.length > 0)               // 移除空字符串
		.map(word => word.replace(/[^a-zA-Z]/g, '')); // 只保留字母
	
	// 找到第一个有意义的单词
	for (let word of words) {
		// 转换为小写进行比较
		let lowercaseWord = word.toLowerCase();
		// 检查是否是忽略词或单个字母
		if (!IgnoreStringInTitle.includes(lowercaseWord) && 
			word.length > 1 && 
			!/^\d+$/.test(word)) {  // 排除纯数字
			// 转换为首字母大写
			return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
		}
	}
	
	// 如果没有找到合适的单词,返回空字符串
	return '';
}

// Configuration
const CONFIG = {
	useJournal: GM_getValue('useJournal', true),  // Default use journal abbreviation
	debug: GM_getValue('debug', false)  // Debug mode
};

// Test data for debug mode
const DEFAULT_TEST_DATA = `@misc{chen2014l2modulispacessymplecticvortices,
      title={$L^2$-moduli spaces of symplectic vortices on Riemann surfaces with cylindrical ends}, 
      author={Bohui Chen and Bai-Ling Wang},
      year={2014},
      eprint={1405.6387},
      archivePrefix={arXiv},
      primaryClass={math.SG},
      url={https://arxiv.org/abs/1405.6387}, 
}`;

// Get stored test data or use default
let TEST_DATA = GM_getValue('testData', DEFAULT_TEST_DATA);

// Function to update test data
function updateTestData(newData) {
	TEST_DATA = newData;
	GM_setValue('testData', newData);
}

// 注册菜单命令
GM_registerMenuCommand('Toggle Journal/Title Mode', function() {
	const currentMode = GM_getValue('useJournal', true);
	const newMode = !currentMode;
	GM_setValue('useJournal', newMode);
	CONFIG.useJournal = newMode;
	
	// 显示当前模式
	const modeText = newMode ? 'Journal Mode' : 'Title Mode';
	alert('Switched to ' + modeText);
	
	// 刷新页面以应用新设置
	location.reload();
});

// Add status indicator
function addStatusIndicator() {
	// Remove existing indicator if any
	const existingIndicator = document.getElementById('mode-indicator');
	if (existingIndicator) {
		existingIndicator.remove();
	}

	const indicator = document.createElement('div');
	indicator.id = 'mode-indicator';
	indicator.style.cssText = `
		position: fixed;
		top: 8px;
		right: 8px;
		padding: 3px 6px;
		background: #f0f0f0;
		border: 1px solid #ccc;
		border-radius: 3px;
		font-size: 12px;
		font-weight: bold;
		z-index: 9999;
		cursor: pointer;
		user-select: none;
		margin-bottom: 3px;
		box-shadow: 0 1px 3px rgba(0,0,0,0.2);
		min-width: 80px;
		text-align: center;
	`;
	indicator.textContent = CONFIG.useJournal ? 'Mode: Journal' : 'Mode: Title';
	
	// Add click handler to toggle mode
	indicator.addEventListener('click', function() {
		const currentMode = GM_getValue('useJournal', true);
		const newMode = !currentMode;
		GM_setValue('useJournal', newMode);
		CONFIG.useJournal = newMode;
		
		// Update indicator text
		this.textContent = newMode ? 'Mode: Journal' : 'Mode: Title';
		
		// Update citation keys immediately
		updateBibTeXEntries();
	});
	
	document.body.appendChild(indicator);
}

// Function to update all BibTeX entries
function updateBibTeXEntries() {
	const els = document.getElementsByTagName('pre');
	for (let i = 0; i < els.length; i++) {
		try {
			const el = els[i];
			const bibdata = parseBibTex(el.innerHTML);
			if (!bibdata) continue;

			// Extract author
			const author = cleanAuthorName(bibdata.author);
			
			// Extract year
			let year = '';
			if (bibdata.year) {
				let yearMatch = bibdata.year.match(/\d{4}/);
				if (yearMatch) {
					year = yearMatch[0];
				}
			}
			
			// Get identifier based on current mode
			let identifier = '';
			if (CONFIG.useJournal && bibdata.journal) {
				identifier = getJournalAbbrev(bibdata.journal);
				if (!identifier) {
					identifier = cleanTitle(bibdata.title);
				}
			} else {
				identifier = cleanTitle(bibdata.title);
			}
			
			// Create new BibTeX key
			const bibkey = author + year + identifier;
			
			// Replace the citation key in the original text
			const originalText = el.innerHTML;
			const newText = originalText.replace(/@([^{]+){([^,\n]+)[,\n]/, `@$1{${bibkey},`);
			
			// Update the content
			el.innerHTML = newText;
			
			// Add click to copy functionality if not already present
			if (!el.hasAttribute('data-click-handler')) {
				el.setAttribute('data-click-handler', 'true');
				el.addEventListener('click', function() {
					try {
						var bibdata_lb = this.innerHTML
							.replace(/\r|\n/g, '\r\n')
							.replace(/^\r\n/g, '')
							.replace(/\s*$/g, '\r\n')
							.replace(/\r\n\r\n/g, '\r\n');
						GM_setClipboard(bibdata_lb);
					} catch (error) {
						console.error('Error copying to clipboard:', error);
					}
				});
			}
		} catch (error) {
			console.error('Error updating BibTeX entry:', error);
		}
	}
}

// 在页面加载完成后添加状态指示器
window.addEventListener('load', function() {
	addStandardizeButton();
	addStatusIndicator();
	addDebugToggle();
	addTestDataButton();
	
	// 检测新AMS MathSciNet网站的引用格式弹窗
	if (isNewAMSSite()) {
		handleNewAMSSite();
	} else {
		// Update all BibTeX entries on page load for old site
		updateBibTeXEntries();
	}
});

// 检测是否为新AMS MathSciNet网站
function isNewAMSSite() {
	return window.location.hostname === 'mathscinet.ams.org' && 
		   window.location.pathname.includes('/mathscinet/');
}

// 处理新AMS MathSciNet网站
function handleNewAMSSite() {
	// 监听引用格式弹窗的出现
	observeCitationModal();
	
	// 为现有的引用格式弹窗添加功能
	enhanceExistingCitationModals();
	
	// 添加定期检查机制,确保捕获到动态创建的弹窗
	setupPeriodicCheck();
}

// 设置定期检查机制
function setupPeriodicCheck() {
	// 每2秒检查一次是否有新的弹窗
	const checkInterval = setInterval(function() {
		// 查找所有未增强的弹窗
		const unenhancedModals = document.querySelectorAll('.modal-content:not([data-enhanced]), [id*="modal"]:not([data-enhanced])');
		
		if (unenhancedModals.length > 0) {
			unenhancedModals.forEach(function(modal) {
				const textarea = modal.querySelector('#citationText');
				if (textarea) {
					enhanceCitationModal(modal);
				}
			});
		}
		
		// 也检查是否有新的文本区域
		const allTextareas = document.querySelectorAll('#citationText');
		allTextareas.forEach(function(textarea) {
			const modal = textarea.closest('.modal-content, [id*="modal"], [class*="modal"]');
			if (modal && !modal.hasAttribute('data-enhanced')) {
				enhanceCitationModal(modal);
			}
		});
		
		// 检查已增强的弹窗中的BibTeX内容是否需要标准化
		const enhancedModals = document.querySelectorAll('.modal-content[data-enhanced], [id*="modal"][data-enhanced]');
		enhancedModals.forEach(function(modal) {
			const textarea = modal.querySelector('#citationText');
			const formatSelect = modal.querySelector('select[name="Select citation format"]');
			
			if (textarea && formatSelect && formatSelect.value === 'bibtex') {
				const content = textarea.value.trim();
				if (content && content.startsWith('@') && content.includes('{') && content.includes('}')) {
					// 检查是否需要标准化
					try {
						const bibdata = parseBibTex(content);
						if (bibdata && bibdata.author && bibdata.year) {
							const expectedKey = generateExpectedKey(bibdata);
							if (bibdata.citationKey !== expectedKey) {
								const newBibtex = generateStandardizedBibTeX(bibdata);
								if (newBibtex && newBibtex !== content) {
									textarea.value = newBibtex;
									showSuccessMessage(modal, 'BibTeX已自动标准化!');
								}
							}
						}
					} catch (error) {
						console.error('定期检查标准化时出错:', error);
					}
				}
			}
		});
	}, 2000);
	
	// 存储interval ID,以便后续清理
	window._mrlookupCheckInterval = checkInterval;
}

// 手动触发标准化(用于调试和手动操作)
function manualTriggerStandardization(modal) {
	const textarea = modal.querySelector('#citationText');
	const formatSelect = modal.querySelector('select[name="Select citation format"]');
	
	if (textarea && formatSelect) {
		const content = textarea.value.trim();
		
		if (content && content.startsWith('@') && content.includes('{') && content.includes('}')) {
			try {
				const bibdata = parseBibTex(content);
				if (bibdata && bibdata.author && bibdata.year) {
					const expectedKey = generateExpectedKey(bibdata);
					
					if (bibdata.citationKey !== expectedKey) {
						const newBibtex = generateStandardizedBibTeX(bibdata);
						if (newBibtex && newBibtex !== content) {
							textarea.value = newBibtex;
							showSuccessMessage(modal, 'BibTeX已手动标准化!');
							return true;
						}
					}
				}
			} catch (error) {
				console.error('手动触发标准化时出错:', error);
			}
		}
	}
	
	return false;
}

// 在弹窗中添加手动触发按钮(用于调试)
function addManualTriggerButton(modal) {
	// 查找按钮容器
	const buttonContainer = modal.querySelector('.modal-footer');
	if (!buttonContainer) return;
	
	// 检查是否已经有手动按钮
	if (modal.querySelector('#manual-trigger-btn')) return;
	
	// 创建手动触发按钮
	const manualBtn = document.createElement('button');
	manualBtn.id = 'manual-trigger-btn';
	manualBtn.textContent = 'Manual Standardize';
	manualBtn.className = 'btn btn-warning';
	manualBtn.style.cssText = `
		margin-right: 10px;
		background-color: #ffc107;
		border-color: #ffc107;
		color: #212529;
		font-size: 12px;
		padding: 4px 8px;
	`;
	
	manualBtn.addEventListener('click', function() {
		manualTriggerStandardization(modal);
	});
	
	// 在关闭按钮前插入手动按钮
	const closeBtn = buttonContainer.querySelector('button[name="Close button"]');
	if (closeBtn) {
		buttonContainer.insertBefore(manualBtn, closeBtn);
	} else {
		buttonContainer.appendChild(manualBtn);
	}
}

// 监听引用格式弹窗的出现
function observeCitationModal() {
	const observer = new MutationObserver(function(mutations) {
		mutations.forEach(function(mutation) {
			if (mutation.type === 'childList') {
				mutation.addedNodes.forEach(function(node) {
					if (node.nodeType === Node.ELEMENT_NODE) {
						// 检查是否包含引用格式弹窗
						if (node.querySelector && node.querySelector('#citationText')) {
							enhanceCitationModal(node);
						}
						// 检查子元素
						const citationTextarea = node.querySelector('#citationText');
						if (citationTextarea) {
							enhanceCitationModal(node);
						}
						
						// 检查是否是新添加的弹窗容器
						if (node.classList && node.classList.contains('modal-content')) {
							// 延迟检查,等待内容加载
							setTimeout(() => {
								const textarea = node.querySelector('#citationText');
								if (textarea) {
									enhanceCitationModal(node);
								}
							}, 100);
						}
					}
				});
			}
		});
	});
	
	observer.observe(document.body, {
		childList: true,
		subtree: true
	});
	
	// 也监听属性变化,因为弹窗可能通过显示/隐藏来工作
	const attributeObserver = new MutationObserver(function(mutations) {
		mutations.forEach(function(mutation) {
			if (mutation.type === 'attributes' && 
				(mutation.attributeName === 'style' || mutation.attributeName === 'class')) {
				
				const target = mutation.target;
				// 检查是否是弹窗相关的元素
				if (target.id && target.id.includes('modal') || 
					target.classList && target.classList.contains('modal-content')) {
					
					// 延迟检查,等待内容完全加载
					setTimeout(() => {
						const textarea = target.querySelector('#citationText');
						if (textarea && !target.hasAttribute('data-enhanced')) {
							enhanceCitationModal(target);
						}
					}, 200);
				}
			}
		});
	});
	
	attributeObserver.observe(document.body, {
		attributes: true,
		subtree: true,
		attributeFilter: ['style', 'class']
	});
}

// 增强现有的引用格式弹窗
function enhanceExistingCitationModals() {
	// 查找所有可能的弹窗容器
	const possibleModals = document.querySelectorAll('.modal-content, [id*="modal"], [class*="modal"]');
	
	possibleModals.forEach(function(modal) {
		const citationTextareas = modal.querySelectorAll('#citationText');
		
		citationTextareas.forEach(function(textarea) {
			if (modal && !modal.hasAttribute('data-enhanced')) {
				enhanceCitationModal(modal);
			}
		});
	});
	
	// 也直接查找文本区域
	const citationTextareas = document.querySelectorAll('#citationText');
	
	citationTextareas.forEach(function(textarea) {
		const modal = textarea.closest('.modal-content, [id*="modal"], [class*="modal"]');
		if (modal && !modal.hasAttribute('data-enhanced')) {
			enhanceCitationModal(modal);
		}
	});
}

// 增强引用格式弹窗
function enhanceCitationModal(modal) {
	if (modal.hasAttribute('data-enhanced')) {
		return;
	}
	
	modal.setAttribute('data-enhanced', 'true');
	
	// 查找引用文本区域
	const citationTextarea = modal.querySelector('#citationText');
	if (!citationTextarea) {
		return;
	}
	
	// 监听引用格式变化(自动标准化)
	observeCitationFormatChange(modal);
	
	// 监听文本区域内容变化(实时标准化)
	observeTextareaContentChange(modal, citationTextarea);
	
	// 添加手动触发按钮
	addManualTriggerButton(modal);
}

// 在引用格式弹窗中添加标准化按钮(已移除,改为自动标准化)
function addStandardizeButtonToModal(modal, textarea) {
	// 此函数已不再使用,保留以避免引用错误
	console.log('自动标准化模式已启用,无需手动按钮');
}

// 监听引用格式变化
function observeCitationFormatChange(modal) {
	const formatSelect = modal.querySelector('select[name="Select citation format"]');
	if (formatSelect) {
		// 移除可能存在的旧监听器
		if (formatSelect._changeHandler) {
			formatSelect.removeEventListener('change', formatSelect._changeHandler);
		}
		
		// 创建新的监听器
		formatSelect._changeHandler = function() {
			// 当格式改变时,等待内容加载完成
			setTimeout(function() {
				const textarea = modal.querySelector('#citationText');
				if (textarea && textarea.value.trim()) {
					// 如果选择了BibTeX格式,自动标准化
					if (this.value === 'bibtex') {
						setTimeout(function() {
							try {
								const currentContent = textarea.value.trim();
								
								const bibdata = parseBibTex(currentContent);
								if (bibdata) {
									const newBibtex = generateStandardizedBibTeX(bibdata);
									if (newBibtex && newBibtex !== currentContent) {
										textarea.value = newBibtex;
										// 显示成功消息
										showSuccessMessage(modal, 'BibTeX已自动标准化!');
									}
								}
							} catch (error) {
								console.error('自动标准化BibTeX时出错:', error);
							}
						}, 500); // 等待内容加载
					}
				}
			}, 100);
		};
		
		formatSelect.addEventListener('change', formatSelect._changeHandler);
		
		// 如果当前已经是BibTeX格式,立即尝试标准化
		if (formatSelect.value === 'bibtex') {
			setTimeout(() => {
				const textarea = modal.querySelector('#citationText');
				if (textarea && textarea.value.trim()) {
					formatSelect._changeHandler.call(formatSelect);
				}
			}, 100);
		}
	}
}

// 监听文本区域内容变化,实现实时标准化
function observeTextareaContentChange(modal, textarea) {
	// 使用MutationObserver监听内容变化
	const observer = new MutationObserver(function(mutations) {
		mutations.forEach(function(mutation) {
			if (mutation.type === 'childList' || mutation.type === 'characterData') {
				// 检查是否包含有效的BibTeX内容
				const content = textarea.value.trim();
				if (content && content.startsWith('@') && content.includes('{') && content.includes('}')) {
					// 延迟执行,避免频繁触发
					setTimeout(function() {
						autoStandardizeIfNeeded(modal, textarea, content);
					}, 300);
				}
			}
		});
	});
	
	// 监听文本区域的变化
	observer.observe(textarea, {
		childList: true,
		characterData: true,
		subtree: true
	});
	
	// 也监听input事件(用户输入)
	textarea.addEventListener('input', function() {
		const content = this.value.trim();
		if (content && content.startsWith('@') && content.includes('{') && content.includes('}')) {
			// 延迟执行,避免频繁触发
			setTimeout(function() {
				autoStandardizeIfNeeded(modal, textarea, content);
			}, 500);
		}
	});
}

// 自动标准化检查
function autoStandardizeIfNeeded(modal, textarea, content) {
	try {
		// 检查是否已经是标准化格式
		const bibdata = parseBibTex(content);
		if (bibdata && bibdata.author && bibdata.year) {
			// 检查引用键是否已经是标准格式
			const expectedKey = generateExpectedKey(bibdata);
			
			if (bibdata.citationKey !== expectedKey) {
				// 需要标准化
				const newBibtex = generateStandardizedBibTeX(bibdata);
				if (newBibtex && newBibtex !== content) {
					textarea.value = newBibtex;
					// 显示成功消息
					showSuccessMessage(modal, 'BibTeX已自动标准化!');
				}
			}
		}
	} catch (error) {
		console.error('自动标准化检查时出错:', error);
	}
}

// 生成期望的引用键(用于检查是否需要标准化)
function generateExpectedKey(bibdata) {
	// 提取作者
	const author = cleanAuthorName(bibdata.author);
	
	// 提取年份
	let year = '';
	if (bibdata.year) {
		let yearMatch = bibdata.year.match(/\d{4}/);
		if (yearMatch) {
			year = yearMatch[0];
		}
	}
	
	// 获取标识符
	let identifier = '';
	if (CONFIG.useJournal && bibdata.journal) {
		identifier = getJournalAbbrev(bibdata.journal);
		if (!identifier) {
			identifier = cleanTitle(bibdata.title);
		}
	} else {
		identifier = cleanTitle(bibdata.title);
	}
	
	// 创建期望的引用键
	return author + year + identifier;
}

// 生成标准化的BibTeX
function generateStandardizedBibTeX(bibdata) {
	// 提取作者
	const author = cleanAuthorName(bibdata.author);
	
	// 提取年份
	let year = '';
	if (bibdata.year) {
		let yearMatch = bibdata.year.match(/\d{4}/);
		if (yearMatch) {
			year = yearMatch[0];
		}
	}
	
	// 获取标识符
	let identifier = '';
	if (CONFIG.useJournal && bibdata.journal) {
		identifier = getJournalAbbrev(bibdata.journal);
		if (!identifier) {
			identifier = cleanTitle(bibdata.title);
		}
	} else {
		identifier = cleanTitle(bibdata.title);
	}
	
	// 创建新的引用键
	const bibkey = author + year + identifier;
	
	// 清理值
	const cleanValue = (value) => {
		if (!value) return '';
		return value.replace(/^{|}$/g, '');
	};
	
	// 获取所有字段名
	const fieldNames = Object.keys(bibdata).filter(key => 
		key !== 'typeName' && key !== 'citationKey'
	).map(key => key.toUpperCase());
	
	// 找到最长的字段名用于对齐
	const maxLength = Math.max(...fieldNames.map(name => name.length));
	
	// 格式化字段
	const formatField = (name, value) => {
		const padding = ' '.repeat(maxLength - name.length);
		const cleanedValue = cleanValue(value);
		return `    ${name}${padding} = {${cleanedValue}},\n`;
	};
	
	// 标准化格式
	let standardized = `@${bibdata.typeName} {${bibkey},\n`;
	
	// 添加所有字段
	for (const field of fieldNames) {
		const value = bibdata[field.toLowerCase()];
		if (value) {
			standardized += formatField(field, value);
		}
	}
	
	// 移除尾随逗号并添加闭合括号
	standardized = standardized.replace(/,\n$/, '\n}');
	
	return standardized;
}

// 显示成功消息
function showSuccessMessage(modal, message) {
	showMessage(modal, message, 'success');
}

// 显示错误消息
function showErrorMessage(modal, message) {
	showMessage(modal, message, 'error');
}

// 显示消息
function showMessage(modal, message, type) {
	// 移除现有消息
	const existingMessage = modal.querySelector('.mrlookup-message');
	if (existingMessage) {
		existingMessage.remove();
	}
	
	// 创建消息元素
	const messageDiv = document.createElement('div');
	messageDiv.className = 'mrlookup-message';
	messageDiv.style.cssText = `
		position: absolute;
		top: 10px;
		right: 10px;
		padding: 8px 12px;
		border-radius: 4px;
		font-size: 12px;
		font-weight: bold;
		z-index: 1000;
		${type === 'success' ? 
			'background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb;' : 
			'background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb;'
		}
	`;
	messageDiv.textContent = message;
	
	// 添加到模态框
	modal.style.position = 'relative';
	modal.appendChild(messageDiv);
	
	// 3秒后自动移除
	setTimeout(function() {
		if (messageDiv.parentNode) {
			messageDiv.parentNode.removeChild(messageDiv);
		}
	}, 3000);
}

// 添加新的期刊处理函数
function getJournalAbbrev(journal) {
	if (!journal) return '';
	
	// 移除LaTeX命令和特殊字符
	journal = journal.replace(/\\[a-zA-Z]+/g, '')     // 移除LaTeX命令
		   .replace(/[{}\\\'"`]/g, '')                // 移除特殊字符
		   .replace(/\([^)]*\)/g, '')                 // 移除括号内容
		   .replace(/\{[^}]*\}/g, '')                 // 移除花括号内容
		   .trim();
	
	// 分割成单词
	let words = journal.split(/[\s.]+/).filter(word => word.length > 0);
	
	if (words.length === 1) {
		// 如果只有一个单词,取前三个字母并转为大写
		return words[0].slice(0, 3).toUpperCase();
	} else {
		// 多个单词时提取大写字母
		let abbrev = journal.match(/[A-Z]/g);
		return abbrev ? abbrev.join('') : '';
	}
}

/**
 * auto set bibtex item checked for mrlookup site
 */
var url = location.pathname;
if (url.includes('mrlookup')) {
	document.getElementsByName('format')[1].checked = true;
}

// Add button to standardize BibTeX
function addStandardizeButton() {
	const button = document.createElement('button');
	button.textContent = 'Standardize BibTeX';
	button.style.cssText = `
		position: fixed;
		top: 45px;
		right: 10px;
		padding: 5px 10px;
		font-size: 12px;
		background: #4CAF50;
		color: white;
		border: none;
		border-radius: 3px;
		cursor: pointer;
		z-index: 9999;
		margin-bottom: 5px;
	`;
	button.addEventListener('click', standardizeBibTeX);
	document.body.appendChild(button);
}

// Add test data button when debug is on
function addTestDataButton() {
	// Remove existing test button if any
	const existingBtn = document.getElementById('test-data-btn');
	if (existingBtn) {
		existingBtn.remove();
	}
	
	// Only add button if debug mode is on
	if (!CONFIG.debug) return;
	
	const testBtn = document.createElement('button');
	testBtn.id = 'test-data-btn';
	testBtn.textContent = 'Test Data';
	testBtn.style.cssText = `
		position: fixed;
		top: 115px;
		right: 10px;
		padding: 5px 10px;
		font-size: 12px;
		background: #4CAF50;
		color: white;
		border: none;
		border-radius: 3px;
		cursor: pointer;
		z-index: 9999;
		margin-bottom: 5px;
	`;
	testBtn.addEventListener('click', () => {
		// First open the dialog
		standardizeBibTeX();
		// Then fill it with test data
		setTimeout(() => {
			const textarea = document.querySelector('textarea');
			if (textarea) {
				textarea.value = TEST_DATA;
			}
		}, 100); // Small delay to ensure dialog is created
	});
	document.body.appendChild(testBtn);
}

// Add debug mode toggle
function addDebugToggle() {
	const debugBtn = document.createElement('button');
	debugBtn.textContent = CONFIG.debug ? 'Debug: ON' : 'Debug: OFF';
	debugBtn.style.cssText = `
		position: fixed;
		top: 80px;
		right: 10px;
		padding: 5px 10px;
		font-size: 12px;
		background: ${CONFIG.debug ? '#ff4444' : '#f0f0f0'};
		color: ${CONFIG.debug ? 'white' : 'black'};
		border: 1px solid #ccc;
		border-radius: 3px;
		cursor: pointer;
		z-index: 9999;
		margin-bottom: 5px;
	`;
	debugBtn.addEventListener('click', function() {
		CONFIG.debug = !CONFIG.debug;
		GM_setValue('debug', CONFIG.debug);
		this.textContent = CONFIG.debug ? 'Debug: ON' : 'Debug: OFF';
		this.style.background = CONFIG.debug ? '#ff4444' : '#f0f0f0';
		this.style.color = CONFIG.debug ? 'white' : 'black';
		
		// Update test data button visibility
		addTestDataButton();
	});
	document.body.appendChild(debugBtn);
}

// Show debug result
function showDebugResult(result) {
	if (!CONFIG.debug) return;
	
	// Remove existing debug result if any
	const existingResult = document.getElementById('debug-result');
	if (existingResult) {
		existingResult.remove();
	}
	
	// Create overlay
	const overlay = document.createElement('div');
	overlay.style.cssText = `
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background: rgba(0,0,0,0.5);
		z-index: 10000;
	`;
	
	const resultDiv = document.createElement('div');
	resultDiv.id = 'debug-result';
	resultDiv.style.cssText = `
		position: fixed;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		background: white;
		padding: 20px;
		border-radius: 5px;
		box-shadow: 0 2px 10px rgba(0,0,0,0.2);
		z-index: 10001;
		width: 80%;
		max-width: 800px;
		max-height: 80vh;
		overflow: auto;
	`;
	
	const pre = document.createElement('pre');
	pre.style.cssText = `
		white-space: pre-wrap;
		word-wrap: break-word;
		font-family: monospace;
		font-size: 14px;
		margin: 0;
		padding: 10px;
		background: #f8f8f8;
		border-radius: 3px;
	`;
	pre.textContent = result;
	
	const closeBtn = document.createElement('button');
	closeBtn.textContent = 'Close';
	closeBtn.style.cssText = `
		position: absolute;
		top: 10px;
		right: 10px;
		padding: 5px 15px;
		background: #f0f0f0;
		border: 1px solid #ccc;
		border-radius: 3px;
		cursor: pointer;
	`;
	closeBtn.onclick = () => {
		document.body.removeChild(overlay);
	};
	
	// Close when clicking outside
	overlay.addEventListener('click', (event) => {
		if (event.target === overlay) {
			document.body.removeChild(overlay);
		}
	});
	
	resultDiv.appendChild(closeBtn);
	resultDiv.appendChild(pre);
	overlay.appendChild(resultDiv);
	document.body.appendChild(overlay);
}

// Modify standardizeBibTeX to handle debug mode
function standardizeBibTeX() {
	// Create dialog container
	const dialog = document.createElement('div');
	dialog.style.cssText = `		position: fixed;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		background: white;
		padding: 20px;
		border-radius: 5px;
		box-shadow: 0 2px 10px rgba(0,0,0,0.2);
		z-index: 10000;
		width: 80%;
		max-width: 800px;
	`;

	// Create textarea
	const textarea = document.createElement('textarea');
	textarea.style.cssText = `
		width: 100%;
		height: 200px;
		margin: 10px 0;
		padding: 10px;
		border: 1px solid #ccc;
		border-radius: 3px;
		font-family: monospace;
		font-size: 14px;
		resize: vertical;
	`;
	textarea.placeholder = 'Paste your BibTeX entry here...';

	// Create buttons container
	const buttons = document.createElement('div');
	buttons.style.cssText = `
		text-align: right;
		margin-top: 10px;
	`;

	// Create cancel button
	const cancelBtn = document.createElement('button');
	cancelBtn.textContent = 'Cancel';
	cancelBtn.style.cssText = `
		padding: 5px 15px;
		margin-right: 10px;
		background: #f0f0f0;
		border: 1px solid #ccc;
		border-radius: 3px;
		cursor: pointer;
	`;

	// Create submit button
	const submitBtn = document.createElement('button');
	submitBtn.textContent = 'Standardize';
	submitBtn.style.cssText = `
		padding: 5px 15px;
		background: #4CAF50;
		color: white;
		border: none;
		border-radius: 3px;
		cursor: pointer;
	`;

	// Create overlay
	const overlay = document.createElement('div');
	overlay.style.cssText = `
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background: rgba(0,0,0,0.5);
		z-index: 9999;
	`;

	// Add event listeners
	cancelBtn.onclick = () => {
		document.body.removeChild(overlay);
	};

	// Close dialog when clicking outside
	overlay.addEventListener('click', (event) => {
		// Only close if clicking directly on the overlay, not its children
		if (event.target === overlay) {
			document.body.removeChild(overlay);
		}
	});

	submitBtn.onclick = () => {
		const input = textarea.value.trim();
		if (!input) {
			alert('Please enter a BibTeX entry');
			return;
		}

		try {
			// Store the input as test data if in debug mode
			if (CONFIG.debug) {
				updateTestData(input);
			}

			// Parse the input BibTeX
			const bibdata = parseBibTex(input);
			if (!bibdata) {
				alert('Invalid BibTeX format');
				return;
			}

			// Clean up the data by removing extra braces and preserving math
			const cleanValue = (value) => {
				if (!value) return '';
				// Remove only the outermost braces if they exist
				// This preserves all LaTeX commands and math formulas
				return value.replace(/^{|}$/g, '');
			};

			// Extract author
			const author = cleanAuthorName(cleanValue(bibdata.author));
			
			// Extract year
			let year = '';
			if (bibdata.year) {
				let yearMatch = cleanValue(bibdata.year).match(/\d{4}/);
				if (yearMatch) {
					year = yearMatch[0];
				}
			}
			
			// Get identifier based on current mode
			let identifier = '';
			if (CONFIG.useJournal && bibdata.journal) {
				identifier = getJournalAbbrev(cleanValue(bibdata.journal));
				if (!identifier) {
					identifier = cleanTitle(cleanValue(bibdata.title));
				}
			} else {
				identifier = cleanTitle(cleanValue(bibdata.title));
			}
			
			// Create new BibTeX key
			const bibkey = author + year + identifier;

			// Get all field names from the input, preserving their original case
			const fieldNames = Object.keys(bibdata).filter(key => 
				key !== 'typeName' && key !== 'citationKey'
			).map(key => key.toUpperCase());

			// Find the longest field name for alignment
			const maxLength = Math.max(...fieldNames.map(name => name.length));

			// Function to format a field with proper alignment
			const formatField = (name, value) => {
				const padding = ' '.repeat(maxLength - name.length);
				// Clean the value and ensure it's properly wrapped in braces
				const cleanedValue = cleanValue(value);
				return `    ${name}${padding} = {${cleanedValue}},\n`;
			};

			// Standardize the format
			let standardized = `@${bibdata.typeName} {${bibkey},\n`;
			
			// Add all fields from the input
			for (const field of fieldNames) {
				const value = bibdata[field.toLowerCase()];
				if (value) {
					standardized += formatField(field, value);
				}
			}

			// Remove trailing comma and add closing brace
			standardized = standardized.replace(/,\n$/, '\n}');

			if (CONFIG.debug) {
				// Show debug result
				showDebugResult(standardized);
			} else {
				// Copy to clipboard
				GM_setClipboard(standardized);
				alert('Standardized BibTeX has been copied to clipboard!');
			}
			document.body.removeChild(overlay);
		} catch (error) {
			console.error('Error standardizing BibTeX:', error);
			alert('Error standardizing BibTeX. Please check the console for details.');
		}
	};

	// Assemble dialog
	buttons.appendChild(cancelBtn);
	buttons.appendChild(submitBtn);
	dialog.appendChild(textarea);
	dialog.appendChild(buttons);
	overlay.appendChild(dialog);
	document.body.appendChild(overlay);

	// Focus textarea
	textarea.focus();
}

// 重新定位所有按钮的函数
function repositionButtons() {
	const modeIndicator = document.getElementById('mode-indicator');
	const standardizeBtn = document.querySelector('button[onclick="standardizeBibTeX()"]');
	const testDataBtn = document.getElementById('test-data-btn');
	const debugBtn = document.getElementById('debug-toggle-btn'); // 使用明确的ID
	
	// 基础位置
	let currentTop = 8;
	
	// Mode Indicator 始终在顶部
	if (modeIndicator) {
		modeIndicator.style.top = currentTop + 'px';
		currentTop += 30; // 按钮高度 + margin
	}
	
	// Standardize Button 始终显示
	if (standardizeBtn) {
		standardizeBtn.style.top = currentTop + 'px';
		currentTop += 30;
	}
	
	// Test Data Button 仅在Debug模式下显示
	if (testDataBtn && CONFIG.debug) {
		testDataBtn.style.top = currentTop + 'px';
		currentTop += 30;
	}
	
	// Debug Button 始终显示,位置根据Test Data按钮是否显示调整
	if (debugBtn) {
		debugBtn.style.top = currentTop + 'px';
	}
	
	// 调试信息
	if (CONFIG.debug) {
		console.log('按钮重新定位完成:');
		console.log('- Mode Indicator:', modeIndicator ? modeIndicator.style.top : 'N/A');
		console.log('- Standardize Button:', standardizeBtn ? standardizeBtn.style.top : 'N/A');
		console.log('- Test Data Button:', testDataBtn ? testDataBtn.style.top : 'N/A');
		console.log('- Debug Button:', debugBtn ? debugBtn.style.top : 'N/A');
	}
}