//Dokumentation unter ] <nowiki>
/*global mediaWiki, ve, OO*/
/*jshint sub: true*/
//jscs:disable requireDotNotation
(function ($, mw) {
"use strict";

mw.messages.set({
	'schnark-nd-open': '?',
	'schnark-nd-remove': 'x',
	'schnark-nd-exchange': '↔',
	'schnark-nd-viaf': '→VIAF',
	'schnark-nd-update': 'Datum aktualisieren',
	'schnark-nd-update-done': 'Datum wurde zum Aktualisieren vorgemerkt',
	'schnark-nd-gnd-title': 'Datensatz zu dieser GND-Nummer (in neuem Tab)',
	'schnark-nd-lccn-title': 'Datensatz zu dieser LCCN-Nummer (in neuem Tab)',
	'schnark-nd-ndl-title': 'Datensatz zu dieser NDL-Nummer (in neuem Tab)',
	'schnark-nd-viaf-title': 'Datensatz zu dieser VIAF-Nummer (in neuem Tab)',
	'schnark-nd-remove-gnd-title': 'GND entfernen',
	'schnark-nd-remove-lccn-title': 'LCCN entfernen',
	'schnark-nd-remove-ndl-title': 'NDL entfernen',
	'schnark-nd-remove-viaf-title': 'VIAF entfernen',
	'schnark-nd-search-gnd-title': 'Suche nach GND (in neuem Tab)',
	'schnark-nd-search-ndl-title': 'Suche nach NDL (in neuem Tab)',
	'schnark-nd-search-viaf-title': 'Suche nach VIAF (in neuem Tab)',
	'schnark-nd-search-viaf-gnd-title': 'Suche nach VIAF-Nummer zu dieser GND (in neuem Tab)',
	'schnark-nd-exchange-title': 'GND und GNDName vertauschen',
	'schnark-nd-wpgndf-title': 'Bitte um Individualisierung einer GND, Meldung von Fehlern (in neuem Tab)',
	'schnark-nd-update-title': 'Datum der letzten Überprüfung von $1 auf aktuelles Datum aktualisieren',
	'schnark-nd-wikidata': 'Wikidata',
	'schnark-nd-headline': 'Bearbeiten der Normdaten',
	'schnark-nd-button-edit': 'Bearbeiten',
	'schnark-nd-button-create': 'Normdaten einfügen',
	'schnark-nd-button-ve': 'Normdaten bearbeiten',
	'schnark-nd-button-ve-title': 'Normdaten bearbeiten oder erstellen',
	'schnark-nd-ve-label': 'Normdaten-Vorlage',
	'schnark-nd-ve-edit': 'Normdaten bearbeiten'
});

var version = '5.22', autocorr, config, globalData, caches, teObject;

config = {
	commentNDneu: '+Normdaten',
	commentNDerw: 'Normdaten ergänzt',
	commentNDkorr: 'Normdaten korrigiert',

	disableExternal: false, //kein Skript von viaf.org/id.ndl.go.jp laden
	debugAjax: false,
	//0: leere Parameter löschen
	//1: leere Parameter behalten
	//2: meisten leere Parameter behalten
	//3: leere Parameter nicht ändern
	full: 3,
	alwaysShowEdit: false //Bearbeiten-Schaltfläche immer anzeigen
};

globalData = {
	$pd: {length: 0},
	$nd: {length: 0},
	gndFehltVorschlag: false, //statt leerer GND ein "fehlt" vorschlagen
	istPerson: false, //Normdaten zu einer Person -> umfangreicheres Interface
	dnbportal: '', //GND in DNB-Portal-Vorlage, falls abweichend von GND
	checkdate: '', //Inhalt von GNDCheck
	leereParameter: , //leere Parameter in ursprünglicher ND-Vorlage
	tELoaded: false
};

caches = {
	viaf: {},
	oldLists: {}
};

function extrahiere (regex, text) { //liefert erste Klammer des regulären Ausdrucks
	return (regex.exec(text) === null ? '' : regex.exec(text));
}

function pad (n) {
	return n < 10 ? '0' + String(n) : String(n);
}

autocorr = {
	gndFehlt: function (gnd) {
		return formatGnd(gnd, true);
	},
	gnd: function (gnd) {
		return formatGnd(gnd);
	},
	lccn: function (lccn) {
		return formatLccn(lccn, false);
	},
	nospace: function (viaf) {
		return viaf.replace(/+/g, '');
	},
	typ: function (typ) {
		typ = typ.replace(/\s/g, '').toLowerCase().slice(0, 1);
		if ('pkvwsg'.indexOf(typ || '?') === -1) {
			typ = '';
		}
		return typ;
	}
};

function addInterface (data) {
	if (globalData.istPerson) {
		addInterfacePerson(data);
	} else {
		addInterfaceOther(data);
	}
}
function addInterfacePerson (data) {
	var title, PDfn, $name, $anamen;

	teObject.addInput('gnd', {text: '<code>GND</code> (Person)', val: data.gnd, autofill: true, autocorr: autocorr.gndFehlt})
		.html(
			mw.html.element('a', {id: 'pen-show-gnd', 'class': 'internal', href: '#',
				title: mw.msg('schnark-nd-gnd-title')}, mw.msg('schnark-nd-open')) + '&nbsp;' +
			mw.html.element('a', {id: 'pen-loesche-gnd', 'class': 'internal', href: '#',
				title: mw.msg('schnark-nd-remove-gnd-title')}, mw.msg('schnark-nd-remove')) + '&nbsp;' +
			mw.html.element('a', {id: 'pen-suche-viaf', 'class': 'internal', href: '#',
				title: mw.msg('schnark-nd-search-viaf-gnd-title')}, mw.msg('schnark-nd-viaf'))
		);

	teObject.addInput('gndname', {text: '<code>GND</code> (Name)', val: data.gndname, autocorr: autocorr.gnd})
		.html(
			mw.html.element('a', {id: 'pen-show-gndname', 'class': 'internal', href: '#',
				title: mw.msg('schnark-nd-gnd-title')}, mw.msg('schnark-nd-open')) + '&nbsp;' +
			mw.html.element('a', {id: 'pen-loesche-gndname', 'class': 'internal', href: '#',
				title: mw.msg('schnark-nd-remove-gnd-title')}, mw.msg('schnark-nd-remove')) + '&nbsp;' +
			mw.html.element('a', {id: 'pen-vertausche-gnd', 'class': 'internal', href: '#',
				title: mw.msg('schnark-nd-exchange-title')}, mw.msg('schnark-nd-exchange'))
		);

	teObject.addInput('lccn', {text: '<code>LCCN</code>', val: data.lccn, autofill: true, autocorr: autocorr.lccn}).html(
		mw.html.element('a', {id: 'pen-show-lccn', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-lccn-title')}, mw.msg('schnark-nd-open')) + '&nbsp;' +
		mw.html.element('a', {id: 'pen-loesche-lccn', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-remove-lccn-title')}, mw.msg('schnark-nd-remove'))
	);

	teObject.addInput('ndl', {text: '<code>NDL</code>', val: data.ndl, /*autofill: true, */ autocorr: autocorr.nospace}).html(
		mw.html.element('a', {id: 'pen-show-ndl', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-ndl-title')}, mw.msg('schnark-nd-open')) + '&nbsp;' +
		mw.html.element('a', {id: 'pen-loesche-ndl', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-remove-ndl-title')}, mw.msg('schnark-nd-remove'))
	);

	teObject.addInput('viaf', {text: '<code>VIAF</code>', val: data.viaf, autofill: true, autocorr: autocorr.nospace}).html(
		mw.html.element('a', {id: 'pen-show-viaf', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-viaf-title')}, mw.msg('schnark-nd-open')) + '&nbsp;' +
		mw.html.element('a', {id: 'pen-loesche-viaf', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-remove-viaf-title')}, mw.msg('schnark-nd-remove'))
	);

	teObject.addInput('sonstige', {text: 'Sonstige', val: data.sonstige});

	title = encodeURIComponent(mw.config.get('wgTitle').replace(/ \(.*$/, ''));
	teObject.addFootitem(mw.html.element('a', {title: mw.msg('schnark-nd-search-viaf-title'),
		target: '_blank', rel: 'noopener',
		href: 'http://www.viaf.org/viaf/search?query=local.names+all+%22' +
			title + '%22&stylesheet=/viaf/xsl/results.xsl&sortKeys=holdingscount'},
		'VIAF'));
	teObject.addFootitem(mw.html.element('a', {title: mw.msg('schnark-nd-search-gnd-title'), target: '_blank', rel: 'noopener',
		href: 'https://portal.dnb.de/opac.htm?method=simpleSearch&query=' +
			title.replace(/%20/g, '+')},
		'DNB'));
	teObject.addFootitem(mw.html.element('a', {title: mw.msg('schnark-nd-search-ndl-title'), target: '_blank', rel: 'noopener',
		href: 'http://id.ndl.go.jp/auth/ndla/?qw=' + title},
		'NDL'));
	teObject.addFootitem(mw.html.element('a', {title: mw.msg('schnark-nd-wpgndf-title'), target: '_blank', rel: 'noopener',
		href: mw.util.getUrl('Wikipedia:GND/Fehlermeldung'), id: 'pd-nd-pndf'},
		'WP:GND/F'));
	if (globalData.checkdate) {
		teObject.addFootitem(mw.html.element('a', {id: 'pen-datum-aktualisieren',
			title: mw.msg('schnark-nd-update-title', globalData.checkdate), href: '#'}, mw.msg('schnark-nd-update')));
		$('#pen-datum-aktualisieren').on('click', datumAktualisieren);
	}

	teObject.get$('gnd').addClass('noime');
	teObject.get$('gndname').addClass('noime');
	teObject.get$('lccn').addClass('noime');
	teObject.get$('ndl').addClass('noime');
	teObject.get$('viaf').addClass('noime');
	teObject.get$('sonstige').addClass('noime');

	$('#pen-show-gnd').on('click', showGnd);
	$('#pen-loesche-gnd').on('click', function () {
		loescheEintrag('gnd');
		return false;
	});
	$('#pen-suche-viaf').on('click', sucheViaf);
	$('#pen-show-gndname').on('click', showGndname);
	$('#pen-loesche-gndname').on('click', function () {
		loescheEintrag('gndname');
		return false;
	});
	$('#pen-vertausche-gnd').on('click', vertauscheGnd);
	$('#pen-show-lccn').on('click', showLccn);
	$('#pen-loesche-lccn').on('click', function () {
		loescheEintrag('lccn');
		return false;
	});
	$('#pen-show-ndl').on('click', showNdl);
	$('#pen-loesche-ndl').on('click', function () {
		loescheEintrag('ndl');
		return false;
	});
	$('#pen-show-viaf').on('click', showViaf);
	$('#pen-loesche-viaf').on('click', function () {
		loescheEintrag('viaf');
		return false;
	});

	startAjax();
	PDfn = getPDfn();
	if (PDfn) {
		$name = PDfn.get$('name');
		if ($name !== null) {
			$name.on('change', function () {
				startAjax(true);
			});
		}
		$anamen = PDfn.get$('alternativnamen');
		if ($anamen !== null) {
			$anamen.on('change', function () {
				startAjax(true);
			});
		}
	}
	teObject.get$('gnd').on('change', startAjax);
	teObject.get$('lccn').on('change', startAjax);
	teObject.get$('viaf').on('change', startAjax);
}
function addInterfaceOther (data) {
	teObject.addInput('typ', {text: '<code>TYP</code>', val: data.typ, autofill: true, autocorr: autocorr.typ});
	teObject.addInput('gnd', {text: '<code>GND</code>', val: data.gnd, autofill: true, autocorr: autocorr.gnd}).html(
		mw.html.element('a', {id: 'pen-show-gnd', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-gnd-title')}, mw.msg('schnark-nd-open')) + '&nbsp;' +
		mw.html.element('a', {id: 'pen-loesche-gnd', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-remove-gnd-title')}, mw.msg('schnark-nd-remove')) /*+ '&nbsp;' +
		mw.html.element('a', {id: 'pen-suche-viaf', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-search-viaf-gnd-title')}, mw.msg('schnark-nd-viaf'))*/
	);
	teObject.addInput('lccn', {text: '<code>LCCN</code>', val: data.lccn, autofill: true, autocorr: autocorr.lccn}).html(
		mw.html.element('a', {id: 'pen-show-lccn', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-lccn-title')}, mw.msg('schnark-nd-open')) + '&nbsp;' +
		mw.html.element('a', {id: 'pen-loesche-lccn', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-remove-lccn-title')}, mw.msg('schnark-nd-remove'))
	);
	teObject.addInput('ndl', {text: '<code>NDL</code>', val: data.ndl, /*autofill: true, */ autocorr: autocorr.nospace}).html(
		mw.html.element('a', {id: 'pen-show-ndl', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-ndl-title')}, mw.msg('schnark-nd-open')) + '&nbsp;' +
		mw.html.element('a', {id: 'pen-loesche-ndl', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-remove-ndl-title')}, mw.msg('schnark-nd-remove'))
	);
	teObject.addInput('viaf', {text: '<code>VIAF</code>', val: data.viaf, autofill: true, autocorr: autocorr.nospace}).html(
		mw.html.element('a', {id: 'pen-show-viaf', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-viaf-title')}, mw.msg('schnark-nd-open')) + '&nbsp;' +
		mw.html.element('a', {id: 'pen-loesche-viaf', 'class': 'internal', href: '#',
			title: mw.msg('schnark-nd-remove-viaf-title')}, mw.msg('schnark-nd-remove'))
	);

	teObject.addInput('sonstige', {text: 'Sonstige', val: data.sonstige});

	var title = encodeURIComponent(mw.config.get('wgTitle').replace(/ \(.*$/, ''));
	teObject.addFootitem(mw.html.element('a', {title: mw.msg('schnark-nd-search-gnd-title'), target: '_blank', rel: 'noopener',
		href: 'https://portal.dnb.de/opac.htm?method=simpleSearch&query=' +
			title.replace(/%20/g, '+')},
		'DNB'));

	teObject.setList('typ', , , ,
		, , ], 'Mögliche Typen');
	teObject.setSuggestions('typ', data.typSugg);
	if (globalData.dnbportal) {
		teObject.setSuggestions('gnd', globalData.dnbportal);
	}

	teObject.get$('typ').addClass('noime');
	teObject.get$('gnd').addClass('noime');
	teObject.get$('lccn').addClass('noime');
	teObject.get$('ndl').addClass('noime');
	teObject.get$('viaf').addClass('noime');
	teObject.get$('sonstige').addClass('noime');

	$('#pen-show-gnd').on('click', showGnd);
	$('#pen-loesche-gnd').on('click', function () {
		loescheEintrag('gnd');
		return false;
	});
	//$('#pen-suche-viaf').on('click', sucheViaf);
	$('#pen-show-lccn').on('click', showLccn);
	$('#pen-loesche-lccn').on('click', function () {
		loescheEintrag('lccn');
		return false;
	});
	$('#pen-show-ndl').on('click', showNdl);
	$('#pen-loesche-ndl').on('click', function () {
		loescheEintrag('ndl');
		return false;
	});
	$('#pen-show-viaf').on('click', showViaf);
	$('#pen-loesche-viaf').on('click', function () {
		loescheEintrag('viaf');
		return false;
	});

	startAjax();
	teObject.get$('gnd').on('change', startAjax);
	//teObject.get$('lccn').on('change', startAjax);
	teObject.get$('viaf').on('change', startAjax);
}

function parseND (text) {
	var nd = extrahiere(/\{\{normdaten\s*\|(*(?:\{\{*\}\}*)*)\}\}/i, text.replace(/<!--.*?-->/g, ''))
			.replace(/\{\{*\}\}|\]*\]\]/g, function (c) {
				return c.replace(/\|/g, '~~~');
			}),
		params = nd.split('|'),
		data = {},
		i, index, feld;
	//Normdaten auslesen
	for (i = 0; i < params.length; i++) {
		params = params.replace(/~~~/g, '|');
		index = params.indexOf('=');
		if (index > -1) {
			data.slice(0, index).replace(/^\s+|\s+$/, '')] = params.slice(index + 1).replace(/^\s+|\s+$/, '');
		}
	}

	data = extrahiere(/\{\{normdaten\s*\|(?:*(?:\{\{*\}\}*)*)\}\}*<!--\s*(.*? *)\s*-->/i, text) +
		(data || '');

	globalData.checkdate = data;
	for (i = 0; i < 4; i++) {
		feld = ;
		if (data === '') {
			globalData.leereParameter.push(feld);
		}
	}
	globalData.dnbportal = extrahiere(/\{\{DNB-Portal\|(*)/, text);

	if (data === 'p' || (!data && (data || data))) {
		globalData.istPerson = true;
	}

	if (globalData.istPerson) {
		return evalNDperson(data);
	} else {
		return evalNDother(data);
	}
}

function evalNDperson (data) {
	var gnd = data || (data || data ? 'fehlt' : ''),
		gndname = data || '',
		lccn = data || '',
		ndl = data || '',
		viaf = data || '',
		sonstige = sonstigeParameter(data);

	if (gnd === 'fehlt') {
		globalData.gndFehltVorschlag = true;
	}

	if (globalData.dnbportal === gnd || globalData.dnbportal === gndname) {
		globalData.dnbportal = ''; //löschen
	}

	return {gnd: gnd, gndname: gndname, lccn: lccn, ndl: ndl, viaf: viaf, sonstige: sonstige};
}
function evalNDother (data) {
	var typ = data || '',
		typSugg = ,
		gnd = data || '',
		lccn = data || '',
		ndl = data || '',
		viaf = data || '',
		sonstige = sonstigeParameter(data);

	//TODO Typ an Kategorien erkennen?
	if (gnd === '') {
		if (data) {
			typSugg = ;
			gnd = data;
		} else if (data) {
			typSugg = ;
			gnd = data;
		}
	}

	if (globalData.dnbportal === gnd) {
		globalData.dnbportal = ''; //löschen
	}

	return {typ: typ, gnd: gnd, lccn: lccn, ndl: ndl, viaf: viaf, sonstige: sonstige, typSugg: typSugg};
}

function sonstigeParameter (data) {
	return 'REMARK' in data && data !== '' ? 'REMARK=' + data : ''; //FIXME
}

function neuerText (text, data) {
	var alteND = extrahiere(/(\{\{normdaten\s*\|*(?:\{\{*\}\}*)*\}\})/i, text.replace(/<!--.*?-->/g, '')),
		altText = text, neueND, pos, comment = false;
	//auskommentierte Normdaten schützen
	text.replace(/<!--(.*?)-->/g, function (c) {
		return '<!--' + c.replace(/\{\{/g, '{~~~{') + '-->';
	});
	//alte Normdaten entfernen
	text = text.replace(/\n*\{\{normdaten\s*\|*(?:\{\{*\}\}*)*\}\}*(?:<!--\s*.*?\s*-->)?/i, '');
	text = text.replace(/\{~~~\{/g, '{{');

	if (globalData.istPerson) {
		neueND = neuerTextPerson(data);
	} else {
		neueND = neuerTextOther(data);
	}

	if (!(/\d/.test(neueND)) && alteND === '') { //keine Zahl: ganz leer
		neueND = '';
	}

	if (neueND !== '') {
		pos = text.indexOf('{{SORTIERUNG');
		if (pos === -1) {
			pos = text.indexOf('{{DEFAULTSORT');
		}
		if (pos === -1) {
			pos = text.indexOf('[[Kategorie:');
		}
		if (pos === -1) {
			pos = text.indexOf('{{Personendaten');
		}
		if (pos === -1) {
			text = text.replace(/\n*$/, '') + '\n\n';
			pos = text.length;
		}
		text = text.slice(0, pos) + neueND + '\n\n' + text.slice(pos);
	}

	if (alteND === '' && (neueND.indexOf('{{Normdaten') > -1)) {
		comment = config.commentNDneu;
	} else if (alteND.replace(//g, '').length < neueND.replace(//g, '').length) {
		comment = config.commentNDerw;
	} else if (altText !== text) {
		comment = config.commentNDkorr;
	}

	return {text: text, comment: comment};
}
function addEmpty (feld, noPerson) {
	switch (config.full) {
		case 0: return false;
		case 1: return true;
		case 2: return noPerson ? feld !== 'LCCN' && feld !== 'NDL' : feld !== 'NDL';
		case 3: return globalData.leereParameter.indexOf(feld) > -1;
	}
}
function neuerTextPerson (data) {
	var nd = '{{Normdaten';
	nd += '|TYP=p';
	if (data.gnd === 'fehlt') {
		if (addEmpty('GND')) {
			nd += '|GND=';
		}
	} else {
		if (data.gnd || addEmpty('GND')) {
			nd += '|GND=' + data.gnd;
		}
	}
	if (data.lccn || addEmpty('LCCN')) {
		nd += '|LCCN=' + data.lccn;
	}
	if (data.ndl || addEmpty('NDL')) {
		nd += '|NDL=' + data.ndl;
	}
	if (data.viaf || addEmpty('VIAF')) {
		nd += '|VIAF=' + data.viaf;
	}
	if (data.gndname) {
		nd += '|GNDName=' + data.gndname;
	}
	if (data.gnd === 'fehlt') {
		nd += '|GNDfehlt=ja';
	}
	if ((data.gndname || (data.gnd === 'fehlt'))) {
		nd += '|GNDCheck=' + isodate(globalData.checkdate || '');
	}
	if (data.sonstige) {
		nd += '|' + data.sonstige;
	}
	nd += '}}';
	return nd;
}
function neuerTextOther (data) {
	var nd = '{{Normdaten';
	if (data.typ) {
		nd += '|TYP=' + data.typ;
	}
	if (data.gnd || addEmpty('GND', true)) {
		nd += '|GND=' + data.gnd;
	}
	if (data.lccn || addEmpty('LCCN', true)) {
		nd += '|LCCN=' + data.lccn;
	}
	if (data.ndl || addEmpty('NDL', true)) {
		nd += '|NDL=' + data.ndl;
	}
	if (data.viaf || addEmpty('VIAF', true)) {
		nd += '|VIAF=' + data.viaf;
	}
	if (data.sonstige) {
		nd += '|' + data.sonstige;
	}
	nd += '}}';
	return nd;
}

//startet alle AJAX-Dinge
function startAjax (dontremove) {
	if (dontremove !== true) {
		addSuggestions({gnd: null, lccn: null, ndl: null, viaf: null});
	}
	var data = teObject.getVal();

	if (data.gnd + data.lccn + data.viaf !== '' && globalData.istPerson) { //bei Nicht-Personen hat VIAF ganz komische GND
		syncGet();
	}

	if (data.gnd === '') {
		if (globalData.dnbportal) {
			addList('gnd', 'dnbportal', ]);
		}
		if (globalData.istPerson) {
			gndsuggGet();
		}
	}
	if (data.ndl === '') {
		ndlsuggGet();
	}
	if (data.viaf === '') {
		viafsuggGet();
	}
	wikidataGet();
}

function addList (feld, typ, list) {
	if (!caches.oldLists.hasOwnProperty(feld)) {
		caches.oldLists = {};
	}
	caches.oldLists = list;
	var completeList = , i;
	for (typ in caches.oldLists) {
		if (caches.oldLists.hasOwnProperty(typ)) {
			for (i = 0; i < caches.oldLists.length; i++) {
				completeList.push(caches.oldLists);
			}
		}
	}
	teObject.setList(feld, completeList);
	return completeList.length;
}

function getPDfn () {
	if (!caches.PDfn) {
		caches.PDfn = teObject.getFunctions('Benutzer:Schnark/js/personendaten.js');
	}
	return caches.PDfn;
}

function getName () {
	if (!globalData.istPerson) {
		return teObject.getTitle().replace(/ \(.+\)$/, '');
	}
	var PDfn = getPDfn(), name = null, $name, pos;
	if (PDfn) {
		name = PDfn.getVal('name');
	}
	if (name !== null) {
		return name;
	} else {
		if (!caches.name) {
			$name = globalData.$pd.find('td').eq(1);
			if ($name.length === 1) {
				caches.name = $name.text().replace(/^\s+/, '').replace(/\s+$/, '');
			} else {
				name = teObject.getTitle().replace(/ \(.+\)$/, '');
				pos = name.lastIndexOf(' ');
				if (pos === -1) {
					caches.name = name;
				} else {
					caches.name = name.slice(pos + 1) + ', ' + name.slice(0, pos);
				}
			}
		}
		return caches.name;
	}
}
function getANamen () {
	var PDfn = getPDfn(), anamen = null, $anamen;
	if (PDfn) {
		anamen = PDfn.getVal('alternativnamen');
	}
	if (anamen !== null) {
		return anamen;
	} else {
		if (!caches.anamen) {
			$anamen = globalData.$pd.find('td').eq(3);
			if ($anamen.length === 1) {
				caches.anamen = $anamen.text().replace(/^\s+/, '').replace(/\s+$/, '');
			} else {
				caches.anamen = '';
			}
		}
		return caches.anamen;
	}
}
function getNameForNDL () {
	var anamen = getANamen().split(';'), i;
	for (i = 0; i < anamen.length; i++) {
		if (//.test(anamen)) {
			return anamen.replace(/ \(.*\)$/, '').replace(/^(.*), (.*)$/, '$2 $1').replace(//g, '');
		}
	}
	return getName().replace(/^(.*), (.*)$/, '$2 $1');
}

function gndsuggGet () {
	//aus </nowiki>]<nowiki>
	var url = 'https://tools.wmflabs.org/persondata/service/gndsearch.php?callback=?';
	$.getJSON(url, {name: getName()}).then(gndsuggRecv);
}
function gndsuggRecv (data) {
	var list = , gnd, text;
	for (gnd in data) {
		if (data.hasOwnProperty(gnd)) {
			text = data;
			if (gnd && text) {
				list.push();
			}
		}
	}
	data = addList('gnd', 'apper', list);
	if (data) {
		globalData.gndFehltVorschlag = true;
	}
}

function ndlsuggGet () {
	if (config.disableExternal) {
		return;
	}
	var sparql = 'PREFIX rda: <http://RDVocab.info/ElementsGr2/>\n' +
			'PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n' +
			'PREFIX xl: <http://www.w3.org/2008/05/skos-xl#>\n' +
			'PREFIX ndl: <http://ndl.go.jp/dcndl/terms/>\n' +
			'SELECT ?uri1 ?birth ?death ?label1 ?label2 WHERE {\n' +
			'?uri1 foaf:primaryTopic ?uri2.\n' +
			'?uri1 xl:prefLabel .\n' +
			'OPTIONAL { ?uri1 xl:prefLabel . }\n' +
			'OPTIONAL { ?uri2 rda:dateOfBirth ?birth. }\n' +
			'OPTIONAL { ?uri2 rda:dateOfDeath ?death. }\n' +
			'?uri2 foaf:name "' + getNameForNDL().replace(/"/g, '') + '".\n' +
			'}',
		url = 'https://id.ndl.go.jp/auth/ndla?callback=?';
	$.getJSON(url, {query: sparql, output: 'json'}).then(ndlsuggRecv);
}
function ndlsuggRecv (data) {
	if (!data || !data.results || !data.results.bindings) {
		return;
	}
	var list = , i, birth, death, uri, label1, label2, date, label, ndl;
	for (i = 0; i < data.results.bindings.length; i++) {
		birth = data.results.bindings.birth;
		death = data.results.bindings.death;
		uri = data.results.bindings.uri1;
		label1 = data.results.bindings.label1;
		label2 = data.results.bindings.label2;
		if (uri && uri.value) {
			ndl = uri.value.slice(31);
		}
		date = ' (' + (birth && birth.value ? birth.value : '') + '–' + (death && death.value ? death.value : '') + ')';
		if (date === ' (–)') {
			date = '';
		}
		label = (label1 && label1.value) ? label1.value : '';
		if (label2 && label2.value && label2 === 'ja-Latn') {
			label = label2.value;
		}
		if (!(/\d/).test(label)) {
			label += date;
		}
		if (label && ndl) {
			list.push();
		}
	}
	addList('ndl', 'ndl', list);
}

function viafGet (name, f) { //TODO hoffen auf ndl
	if (config.disableExternal) {
		return;
	}
	var url = 'https://viaf.org/viaf/AutoSuggest?callback=?';
	name = name.toLowerCase();
	if (!caches.viaf.hasOwnProperty(name)) {
		caches.viaf = $.getJSON(url, {query: name});
	}
	caches.viaf.then(function (data) {
		viafRecv(data, f);
	});
}
function viafRecv (data, f) {
	var neuName = '', name;
	if (data && data.query && data.result === null && globalData.istPerson) { //kein Treffer? -> variieren
		name = data.query;
		if (name.indexOf(',') === -1) {
			if (name.indexOf(' ') !== -1) { //mit Komma probieren
				neuName = name.replace(/ /, ', ');
			}
		} else {
			neuName = name.replace(/,\s*\S+/, ',').replace(/,$/, ''); //ein Vorname weniger
		}
	}
	if (neuName !== '') {
		viafGet(neuName, f);
	} else {
		f(data);
	}
}

function viafsuggGet () {
	viafGet(getName(), viafsuggRecv);
}
function viafsuggRecv (data) {
	if (!data || !data.result) {
		return;
	}
	var list = , i;
	for (i = 0; i < data.result.length; i++) {
		if (!globalData.istPerson || data.result.term.indexOf(' | ') === -1) { //Werke
			list.push(.term, data.result.viafid]);
		}
	}
	addList('viaf', 'viaf', list);
}

function syncGet () {
	viafGet(getName(), syncRecv);
}
function syncRecv (data) {
	var suggestions = {gnd: null, lccn: null, viaf: null}, matches = , i,
		nd = teObject.getVal(), e, m = {gnd: , lccn: , viaf: };
	if (!data || !data.result) {
		return addSuggestions(suggestions);
	}
	for (i = 0; i < data.result.length; i++) {
		e = data.result;
		if (e.dnb === undefined) {
			e.dnb = '?';
		}
		if (e.dnb !== '?') {
			e.dnb = formatGnd(e.dnb);
		}
		if (e.lc === undefined) {
			e.lc = '?';
		}
		if (e.lc !== '?') {
			e.lc = formatLccn(e.lc, false);
		}
		if (e.viafid === undefined) { //sollte nicht passieren
			e.viafid = '?';
		}
		if (e.dnb === nd.gnd || e.dnb === nd.gndname || e.lc === nd.lccn || e.viafid === nd.viaf) {
			matches.push(e);
		}
	}
	for (i = 0; i < matches.length; i++) {
		if (matches.dnb !== '?' && m.gnd.indexOf(matches.dnb) === -1) {
			m.gnd.push(matches.dnb);
		}
		if (matches.lc !== '?' && m.lccn.indexOf(matches.lc) === -1) {
			m.lccn.push(matches.lc);
		}
		if (matches.viafid !== '?' && m.viaf.indexOf(matches.viafid) === -1) {
			m.viaf.push(matches.viafid);
		}
	}
	if (m.gnd.length) {
		globalData.gndFehltVorschlag = true;
	}
	if (m.gnd.length > 0 && m.gnd.length < m.viaf.length) {
		m.gnd.push(globalData.gndFehltVorschlag ? 'fehlt' : '');
	}
	if (m.lccn.length > 0 && m.lccn.length < m.viaf.length) {
		m.lccn.push('');
	}

	if (nd.gndname) {
		i = m.gnd.indexOf(nd.gndname);
		if (i !== -1) {
			m.gnd.splice(i, 1);
		}
	}

	if (m.gnd.length === 0) {
		suggestions.gnd = globalData.gndFehltVorschlag ? 'fehlt' : '';
	} else {
		suggestions.gnd = m.gnd;
	}
	if (m.lccn.length === 0) {
		suggestions.lccn = '';
	} else {
		suggestions.lccn = m.lccn;
	}
	if (m.viaf.length === 0) {
		suggestions.viaf = '';
	} else {
		suggestions.viaf = m.viaf;
	}

	addSuggestions(suggestions);
}

function wikidataGet () {
	var url = 'https://www.wikidata.org/w/api.php?callback=?';
	$.getJSON(url, {action: 'wbgetentities', format: 'json', formatversion: 2, sites: 'dewiki',
		props: 'claims', languages: 'de', titles: teObject.getTitle()}).then(wikidataRecv);
}
function wikidataRecv (data) {
	if (!data || !data.entities || !data.success) {
		return;
	}
	var q, d, i, list, v, curdata = teObject.getVal();
	for (q in data.entities) { //trotz formatversion=2 notwendig :-(
		if (data.entities.hasOwnProperty(q)) {
			d = data.entities;
		}
	}
	d = d.claims;
	if (!d) {
		return;
	}
	if (d.P227) {
		list = ;
		for (i = 0; i < d.P227.length; i++) {
                    if (d.P227.rank != 'deprecated') {
			v = d.P227.mainsnak.datavalue.value;
			if (v !== curdata.gnd) {
				list.push();
			}
                    }
		}
		if (list.length) {
			addList('gnd', 'wikidata', list);
		}
	}
	if (d.P244) {
		list = ;
		for (i = 0; i < d.P244.length; i++) {
                    if (d.P244.rank != 'deprecated') {
			v = formatLccn(d.P244.mainsnak.datavalue.value, false);
			if (v !== curdata.lccn) {
				list.push();
			}
                    }
		}
		if (list.length) {
			addList('lccn', 'wikidata', list);
		}
	}
	if (d.P349) {
		list = ;
		for (i = 0; i < d.P349.length; i++) {
                    if (d.P349.rank != 'deprecated') {
			v = d.P349.mainsnak.datavalue.value;
			if (v !== curdata.ndl) {
				list.push();
			}
                    }
		}
		if (list.length) {
			addList('ndl', 'wikidata', list);
		}
	}
	if (d.P214) {
		list = ;
		for (i = 0; i < d.P214.length; i++) {
                    if (d.P214.rank != 'deprecated') {
			v = d.P214.mainsnak.datavalue.value;
			if (v !== curdata.viaf) {
				list.push();
			}
                    }
		}
		if (list.length) {
			addList('viaf', 'wikidata', list);
		}
	}
}

function addSuggestions (sugg) {
	teObject.setSuggestions('gnd', sugg.gnd);
	teObject.setSuggestions('lccn', sugg.lccn);
	if (globalData.istPerson && sugg.ndl !== undefined) {
		teObject.setSuggestions('ndl', sugg.ndl);
	}
	teObject.setSuggestions('viaf', sugg.viaf);
}

//formatiert datum als yyyy-mm-dd
function isodate (datum) {
	var match, jahr, monat, tag, jetzt;
	if (datum !== '') {
		if (/^\d{4}-\d{2}-\d{2}$/.test(datum)) {
			return datum;
		}
		match = /^\s*(\d\d?)(?:\W+)(\w+)(?:\W+)(\d{2}(?:\d{2})?)\s*$/.exec(datum);
		if (match) {
			tag = Number(match);
			jahr = Number(match);
			if (jahr < 100) {
				jahr += 2000;
			}
			monat = match.toLowerCase();
			if (monat.indexOf('feb') === 0) {
				monat = '2';
			}
			if (monat.indexOf('mär') === 0) {
				monat = '3';
			}
			if (monat.indexOf('apr') === 0) {
				monat = '4';
			}
			if (monat.indexOf('mai') === 0) {
				monat = '5';
			}
			if (monat.indexOf('jun') === 0) {
				monat = '6';
			}
			if (monat.indexOf('jul') === 0) {
				monat = '7';
			}
			if (monat.indexOf('aug') === 0) {
				monat = '8';
			}
			if (monat.indexOf('sep') === 0) {
				monat = '9';
			}
			if (monat.indexOf('okt') === 0) {
				monat = '10';
			}
			if (monat.indexOf('nov') === 0) {
				monat = '11';
			}
			if (monat.indexOf('dez') === 0) {
				monat = '12';
			}
			if (/\D/.test(monat)) {
				monat = '1';
			}
			monat = Number(monat);
		}
	}
	if (!jahr) {
		jetzt = new Date();
		jahr = jetzt.getFullYear();
		monat = jetzt.getMonth() + 1;
		tag = jetzt.getDate();
	}
	return String(jahr) + '-' + pad(monat) + '-' + pad(tag);
}

function formatGnd (gnd, fehlt) {
	gnd = gnd.replace(/+/g, '').replace(/x/, 'X');
	if (!fehlt || gnd === '' || (/^\d+X?$/).test(gnd)) {
		return gnd;
	}
	return 'fehlt';
}
/*formatiert eine LCCN
	gliederung:
		false: ohne Schrägstriche, mit führenden 0
		true: mit Schrägstrichen, ohne führende 0
*/
function formatLccn (lccn, gliederung) {
	lccn = lccn.toLowerCase().replace(/+/g, '').replace(/-/g, '/').replace(/\D+$/, '');
	if (lccn === '') {
		return '';
	}
	var pos = lccn.lastIndexOf('/'), nullen, treffer;
	if (pos > -1) {
		nullen = '000000'.slice(0, -(lccn.length - pos - 1)); //führende 0
		lccn = lccn.replace(/\/(*)$/, nullen + '$1').replace(/\//g, '');
	}
	if (!gliederung) {
		return lccn;
	}
	treffer = /(*)(\d*)(\d{6})$/.exec(lccn);
	if (treffer === null) {
		return '';
	}
	return treffer + '/' + treffer + '/' + treffer.replace(/^0*/, '');
}
function showGnd () {
	var gnd = teObject.getVal('gnd'), url, title;
	if (gnd) {
		url = 'http://d-nb.info/gnd/' + gnd;
	} else {
		title = encodeURIComponent(mw.config.get('wgTitle').replace(/ \(.*$/, ''));
		url = 'https://portal.dnb.de/opac.htm?method=simpleSearch&query=' + title.replace(/%20/g, '+');
	}
	open(url);
	return false;
}
function showGndname () {
	var gnd = teObject.getVal('gndname'), url, title;
	if (gnd) {
		url = 'http://d-nb.info/gnd/' + gnd;
	} else {
		title = encodeURIComponent(mw.config.get('wgTitle').replace(/ \(.*$/, ''));
		url = 'https://portal.dnb.de/opac.htm?method=simpleSearch&query=' + title.replace(/%20/g, '+');
	}
	open(url);
	return false;
}
function showLccn () {
	var lccn = formatLccn(teObject.getVal('lccn'), false), url, title;
	if (lccn) {
		url = 'http://lccn.loc.gov/' + lccn;
	} else {
		title = encodeURIComponent(mw.config.get('wgTitle').replace(/ \(.*$/, ''));
		url = 'http://id.loc.gov/search/?q=' + title.replace(/%20/g, '+');
	}
	open(url);
	return false;
}
function showNdl () {
	var ndl = teObject.getVal('ndl'), url, title;
	if (ndl) {
		url = 'http://id.ndl.go.jp/auth/ndlna/' + ndl;
	} else {
		title = encodeURIComponent(mw.config.get('wgTitle').replace(/ \(.*$/, ''));
		url = 'http://id.ndl.go.jp/auth/ndla/?qw=' + title;
	}
	open(url);
	return false;
}
function showViaf () {
	var viaf = teObject.getVal('viaf'), url, title;
	if (viaf) {
		url = 'http://viaf.org/viaf/' + viaf;
	} else {
		title = encodeURIComponent(mw.config.get('wgTitle').replace(/ \(.*$/, ''));
		url = 'http://www.viaf.org/viaf/search?query=local.names+all+%22' + title +
			'%22&stylesheet=/viaf/xsl/results.xsl&sortKeys=holdingscount';
	}
	open(url);
	return false;
}
function vertauscheGnd () {
	var gnd1 = teObject.getVal('gnd'),
		gnd2 = teObject.getVal('gndname');
	if (gnd1 === 'fehlt') {
		gnd1 = '';
	}
	teObject.setVal('gnd', gnd2);
	teObject.setVal('gndname', gnd1);
	return false;
}
function sucheViaf () {
	var url = 'http://viaf.org/viaf/search?query=local.personalNames+all+%22';
	url += teObject.getVal('gnd');
	url += '%22+and+local.sources+any+%22dnb%22&stylesheet=/viaf/xsl/results.xsl&sortKeys=holdingscount&maximumRecords=100';
	open(url);
	return false;
}
function loescheEintrag (id) {
	teObject.setVal(id, '');
}
function datumAktualisieren () {
	var $link = $('#pen-datum-aktualisieren');
	$link.replaceWith(mw.html.element('b', {title: mw.msg('schnark-nd-update-done')},
		new mw.html.Raw($link.html())));
	globalData.checkdate = isodate('');
	return false;
}

//Anbindung an templateEditor
function waitForTE (f, force) {
	var load = true;
	function f2 (tE) {
		load = false;
		mw.hook('userjs.load-script.templateEditor').remove(f2);
		f(tE);
	}
	mw.hook('userjs.load-script.templateEditor').add(f2);
	if (load && force && !globalData.tELoaded) {
		//</nowiki>]<nowiki>
		mw.loader.load('https://de.wikipedia.org/w/index.php?title=Benutzer:Schnark/js/templateEditor.js' +
			'&action=raw&ctype=text/javascript');
		globalData.tELoaded = true;
	}
}

function lookForND ($content, ve) {
	if ($content.attr('id') !== 'mw-content-text') {
		return;
	}
	globalData.$pd = $content.find('#Vorlage_Personendaten');
	globalData.$nd = $content.find('#normdaten');
	globalData.istPerson = !!globalData.$pd.length;
	if (ve || globalData.$nd.length === 1 || (globalData.$nd.length === 0 && config.alwaysShowEdit)) {
		waitForTE(function () {
			makeButton(ve);
		}, true);
	}
}

function register (tE) {
	var ret = tE('Benutzer:Schnark/js/personendaten.js/normdaten.js', 'nd', version, {
			onStart: onStart,
			onReady: onReady,
			onFinish: onFinish
		});
	if (ret) {
		teObject = ret;
	}
}

function start (ve) {
	$('#ndeditbutton').remove();
	var $div;
	if (!ve) {
		$div = $('<div>');
		if (globalData.$nd.length) {
			globalData.$nd.after($div);
		} else {
			$('#catlinks').after($div);
		}
	}
	teObject.start({headline: mw.msg('schnark-nd-headline'), $: $div});
}

function onStart (script) {
	$('#ndeditbutton').remove();
	if (script.id === 'Benutzer:Schnark/js/personendaten.js') {
		globalData.istPerson = true;
		return 1;
	}
	return 0;
}

function onReady () {
	var text = teObject.getText(), nd = parseND(text);
	addInterface(nd);
}

function onFinish () {
	var text = teObject.getText(),
		nd = teObject.getVal(),
		ret = neuerText(text, nd);
	if (ret.comment) {
		teObject.addComment(ret.comment);
	}
	/* if (!ret.minor) {
		teObject.setNotMinor();
	}*/
	teObject.setText(ret.text);
}

function makeButton (ve) {
	var button, $el;
	if (!teObject) {
		return;
	}
	$('#ndeditbutton').remove();
	if (ve) {
		addLinkForVE();
		return;
	}
	button = mw.html.element('input', {
		id: 'ndeditbutton', type: 'button',
		value: globalData.$nd.length ? mw.msg('schnark-nd-button-edit') : mw.msg('schnark-nd-button-create'),
		'class': 'noprint'
	});
	if (globalData.$nd.length) {
		$el = globalData.$nd.append(button);
	} else {
		$el = $((config.alwaysShowEdit === true) ? '#catlinks' : config.alwaysShowEdit).after(button);
	}
	$('#ndeditbutton').on('click', function () {
		start(false);
	});
}

function extendVE () {
	if (ve.ui.contextItemFactory.lookup('normdaten')) {
		return;
	}

	function NormdatenTemplateContextItem () {
		NormdatenTemplateContextItem.parent.apply(this, arguments);
	}

	OO.inheritClass(NormdatenTemplateContextItem, ve.ui.MWTransclusionContextItem);

	NormdatenTemplateContextItem.static.name = 'normdaten';
	NormdatenTemplateContextItem.static.icon = 'userAvatar';
	NormdatenTemplateContextItem.static.label = mw.msg('schnark-nd-ve-label');
	NormdatenTemplateContextItem.static.isCompatibleWith = function (model) {
		var rawTitle, title;
		if (!NormdatenTemplateContextItem.parent.static.isCompatibleWith.apply(this, arguments)) {
			return false;
		}
		rawTitle = ve.getProp(model.getAttribute('mw'), 'parts', 0, 'template', 'target', 'wt') || '';
		title = mw.Title.newFromText(rawTitle.trim(), 10);
		return !!title && title.getRelativeText(10) === 'Normdaten';
	};

	NormdatenTemplateContextItem.prototype.renderBody = function () {
		var editButton = new OO.ui.ButtonWidget({
				label: mw.msg('schnark-nd-ve-edit')
			}).on('click', function () {
				start(true);
			});
		NormdatenTemplateContextItem.parent.prototype.renderBody.apply(this, arguments);
		this.$body.append(editButton.$element);
	};

	ve.ui.contextItemFactory.register(NormdatenTemplateContextItem);
}

function addLinkForVE () {
	$('#ndeditbutton-ve').remove();
	$(mw.util.addPortletLink(
		'p-tb', '#', mw.msg('schnark-nd-button-ve'), 'ndeditbutton-ve',
		mw.msg('schnark-nd-button-ve-title')
	)).on('click', function (e) {
		e.preventDefault();
		start(true);
	});
	mw.loader.using().then(extendVE);
}

function mockjax (urls) {
	$.ajaxPrefilter(function (o, opts) {
		var url = opts.url.replace(/^(?:https?:)?\/\//, '').replace(/\?callback=\?$/, '');
		if (url in urls) {
			o.mock = urls;
			return 'mock';
		}
	});
	$.ajaxTransport('mock', function (o) {
		o.dataTypes = o.dataTypes.filter(function (dt) {
			return dt !== 'mock';
		});
		var cb = mw.util.getParamValue('callback', o.url);
		return {
			send: function (h, callback) {
				callback(200, 'success', {text: cb + '(' + o.mock + ')'});
			},
			abort: $.noop
		};
	});
}

function backCompat () {
	var oldConfig = $.extend({}, config), key;
	$(document).trigger('loadWikiScript', );
	for (key in oldConfig) {
		if (oldConfig !== config) {
			mw.log.warn('Bitte aktualisiere die Konfiguration für Benutzer:Schnark/js/personendaten.js/normdaten.js!');
			return;
		}
	}
}

function init (ve) {
	if (ve || (mw.config.get('wgNamespaceNumber') === 0 && window.location.search.indexOf('oldid') === -1)) {
		mw.loader.using('mediawiki.util').then(function () {
			waitForTE(register);
			mw.hook('wikipage.content').add(function ($content) {
				lookForND($content, ve);
			});
		});
	}
}

backCompat(); //legacy
mw.hook('userjs.load-script.normdaten').fire(config);

if (mw.config.get('wgServer') === 'http://localhost') {
	config.debugAjax = true;
}
if (config.debugAjax) {
	//jscs:disable maximumLineLength
	mockjax({
	'tools.wmflabs.org/persondata/service/gndsearch.php': '{"130586552":"Brooks, Albert (1947-)","118529579":"Einstein, Albert (1879-1955)"}',
	'id.ndl.go.jp/auth/ndla': '{"head":{"vars":},"results":{"bindings":}}',
	'viaf.org/viaf/AutoSuggest': '{"query":"einstein, albert","result":}',
	'www.wikidata.org/w/api.php': '{"entities":{"Q937":{"id":"Q937","type":"item","claims":{"P214":}],"P227":}],"P244":}]}}},"success":1}'
	});
	//jscs:enable maximumLineLength
}

init();
mw.hook('ve.activationComplete').add(function () {
	if (!ve.init.target.getSurface().isReadOnly()) {
		init(true);
	}
});
mw.hook('ve.deactivationComplete').add(function () {
	$('#ndeditbutton-ve').remove();
});

})(jQuery, mediaWiki);
//</nowiki>