$( function() {
	'use strict';
	var projectskey = 'gadget-eventstreams-projects';
	var excludeduserskey = 'gadget-eventstreams-excludedusers';
	var soundfilekey = 'gadget-eventstreams-soundfile';
	var botkey = 'gadget-eventstreams-bot';
	var settingsbuttontext = 'Settings';
	var settingsbuttontitle = 'Settings for EventStreams';
	var projectslabel = 'Select which project or projects you want to watch, for example <code>eswiki</code>, <code>frwiktionary</code> or <code>dewikivoyage</code>. Separate with newline.';
	var excludeuserslabel = 'Exclude users (separate with newline)';
	var soundfilelabel = 'Sound file to play when a filter is triggered';
	var botlabel = 'Show bot actions';
	var closetext = 'Close';
	var v = mw.config.get();
	var container = $( '#mw-content-text' ).children( '.mw-parser-output' );
	var error = 'The web browser does not support EventSource.';
	var separator = '<span class="gadget-eventstreams-separator"> .. </span>';
	var enc = mw.util.wikiUrlencode;
	var esc = mw.html.escape;
	var diff = 'diff';
	var typenew = 'New page';
	var logtypemove = 'moved';
	var from = ' from ';
	var to = ' to ';
	var logactionmoveredir = ' over a redirect';
	var logtypemovesuppressredirect = ' without leaving a redirect';
	var logactiondelete = 'deleted';
	var logactionrestore = 'restored';
	var logactiondeleteredir = 'deleted redirect';
	var logactionrevision = 'changed visibility for';
	var logactionevent = 'changed visibility for log action';
	var logactioncreate = 'New user';
	var logactioncreate2 = 'created account';
	var logactionbyemail = 'password was sent by email';
	var logactionblock = 'blocked';
	var logactionreblock = 'changed block settings for';
	var logactionunblock = 'unblocked';
	var logactionprotect = 'protected';
	var logactionmodify = 'changed protection settings for';
	var logactionunprotect = 'unprotected';
	var logactionrenameuser = 'renamed';
	var logactionchange = 'changed content model for';
	var logactionrights = 'changed user groups for';
	var logactionautopromote = 'autopromoted';
	var logactionmerge = 'merged';
	var into = 'into';
	var abusefiltermodify = 'changed filter';
	var abusefilterhit = 'triggered filter';
	var globalabusefilterhit = 'triggered global filter';
	var logactionthank = 'thanked';
	var logactionpatrol = 'patrolled';
	var lastSavedTimestamp;
	var savedIds = new Set();
	var wdcommentprefixes = [
		'/* wbsetdescription-set:1|' + v.wgContentLanguage + ' */ ',
		'/* wbsetdescription-remove:1|' + v.wgContentLanguage + ' */ ',
		'/* wbsetdescription-add:1|' + v.wgContentLanguage + ' */ '
	];
	function getProjects() {
		var projectsoutput = mw.storage.get( projectskey );
		if ( projectsoutput ) {
			projectsoutput = projectsoutput.trim();
			if ( projectsoutput ) {
				return projectsoutput.split( '\n' );
			}
		}
		return ;
	}
	function getExcludedUsers() {
		var excludedusersoutput = mw.storage.get( excludeduserskey );
		if ( excludedusersoutput ) {
			excludedusersoutput = excludedusersoutput.trim();
			if ( excludedusersoutput ) {
				return excludedusersoutput.split( '\n' );
			}
		}
		return ;
	}
	function getSoundFile() {
		var soundFile = mw.storage.get( soundfilekey );
		if ( soundFile ) {
			soundFile = soundFile.trim();
			if ( soundFile ) {
				return soundFile;
			}
		}
	}
	function playSound() {
		var soundFile = getSoundFile();
		if ( soundFile ) {
			( new Audio( soundFile ) ).play();
		}
	}
	function getBot() {
		return mw.storage.get( botkey );
	}
	function connect( lastTimestamp ) {
		var url = 'https://stream.wikimedia.org/v2/stream/recentchange';
		if ( lastTimestamp ) {
			url += '?since=' + lastTimestamp;
		}
		var eventSource = new EventSource( url );
		eventSource.onmessage = function( msg ) {
			var data = JSON.parse( msg.data );
			var str = '';
			var user = '<a class="gadget-eventstreams-user" href="' + data.server_url + 'https://wiki95.com/sv/';
			if ( mw.util.isIPAddress( data.user ) ) {
				user += 'Special:Contributions/';
			} else {
				user += 'User:';
			}
			user += esc( enc( data.user ) ) + '">' + data.user + '</a>';
			var title = '<a class="gadget-eventstreams-title" href="' + data.server_url + 'https://wiki95.com/sv/' + esc( enc( data.title ) ) + '">' + data.title + '</a>';
			function startsWithWDCommentPrefix( v ) {
				return data.comment.startsWith( v );
			}
			if ( ( getProjects() ).includes( data.wiki ) || ( data.wiki === 'wikidatawiki' && wdcommentprefixes.some( startsWithWDCommentPrefix ) ) ) {
				if ( !( data.bot && !getBot() ) ) {
					if ( data.type !== 'categorize' ) {
						if ( !( getExcludedUsers() ).includes( data.user ) ) {
							if ( !savedIds.has( data.meta.id ) ) {
								str += '<li class="gadget-eventstreams-listitem" data-type="' + data.type + '" data-id="' + data.meta.id + '" data-timestamp="' + data.timestamp + '"';
								if ( data.type === 'edit' ) {
									str += ' data-revid="' + data.revision.new + '">';
									str += '<a class="gadget-eventstreams-diff" href="' + data.server_url + 'https://wiki95.com/sv/Special:Diff/' + data.revision.new + '">' + diff + '</a>';
									str += separator;
									str += title;
									str += separator;
									str += user;
								} else if ( data.type === 'new' ) {
									str += ' data-revid="' + data.revision.new + '">';
									str += typenew;
									str += separator;
									str += title;
									str += separator;
									str += user;
								} else if ( data.type === 'log' ) {
									str += ' data-logtype="' + data.log_type + '" data-logaction="' + data.log_action + '" data-logid="' + data.log_id + '">';
									if ( data.log_type === 'move' ) {
										str += user;
										str += separator;
										str += logtypemove;
										str += separator;
										str += title;
										str += to;
										str += '<a href="' + data.server_url + 'https://wiki95.com/sv/' + esc( enc( data.log_params.target ) ) + '">' + data.log_params.target + '</a>';
										if ( data.log_action === 'move_redir' ) {
											str += logactionmoveredir;
										}
										if ( data.log_params.noredir === '1' ) {
											str += logtypemovesuppressredirect;
										}
									} else if ( data.log_type === 'delete' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'delete' ) {
											str += logactiondelete;
										} else if ( data.log_action === 'restore' ) {
											str += logactionrestore;
										} else if ( data.log_action === 'delete_redir' ) {
											str += logactiondeleteredir;
										} else if ( data.log_action === 'revision' ) {
											str += logactionrevision;
										} else if ( data.log_action === 'event' ) {
											str += logactionevent;
										}
										str += separator;
										str += title;
									} else if ( data.log_type === 'newusers' ) {
										if ( data.log_action === 'create' ) {
											str += logactioncreate;
											str += separator;
											str += user;
										} else if ( data.log_action === 'create2' ) {
											str += user;
											str += separator;
											str += logactioncreate2;
											str += separator;
											str += title;
										} else if ( data.log_action === 'byemail' ) {
											str += user;
											str += separator;
											str += logactioncreate2;
											str += separator;
											str += title;
											str += separator;
											str += logactionbyemail;
										}
									} else if ( data.log_type === 'block' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'block' ) {
											str += logactionblock;
											str += separator;
											str += title;
											str += separator;
											str += data.log_params.duration;
										} else if ( data.log_action === 'reblock' ) {
											str += logactionreblock;
											str += separator;
											str += title;
										} else if ( data.log_action === 'unblock' ) {
											str += logactionunblock;
											str += separator;
											str += title;
										}
									} else if ( data.log_type === 'protect' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'protect' ) {
											str += logactionprotect;
										} else if ( data.log_action === 'modify' ) {
											str += logactionmodify;
										} else if ( data.log_action === 'unprotect' ) {
											str += logactionunprotect;
										}
										str += separator;
										str += title;
									} else if ( data.log_type === 'renameuser' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'renameuser' ) {
											str += logactionrenameuser;
										}
										str += separator;
										str += '<a href="' + data.server_url + 'https://wiki95.com/sv/User:' + esc( enc( data.log_params.olduser ) ) + '">' + data.log_params.olduser + '</a>';
										str += to;
										str += '<a href="' + data.server_url + 'https://wiki95.com/sv/User:' + esc( enc( data.log_params.newuser ) ) + '">' + data.log_params.newuser + '</a>';
									} else if ( data.log_type === 'contentmodel' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'change' ) {
											str += logactionchange;
										}
										str += separator;
										str += title;
										str += from;
										str += data.log_params.oldmodel;
										str += to;
										str += data.log_params.newmodel;
									} else if ( data.log_type === 'rights' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'rights' ) {
											str += logactionrights;
										} else if ( data.log_action === 'autopromote' ) {
											str += logactionautopromote;
										}
										str += separator;
										str += title;
									} else if ( data.log_type === 'merge' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'merge' ) {
											str += logactionmerge;
										}
										str += separator;
										str += title;
										str += separator;
										str += into;
										str += separator;
										str += '<a href="' + data.server_url + 'https://wiki95.com/sv/' + esc( enc( data.log_params.dest ) ) + '">' + data.log_params.dest + '</a>';
									} else if ( data.log_type === 'abusefilter' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'modify' ) {
											str += abusefiltermodify;
											str += separator;
											str += '<a href="' + data.server_url + 'https://wiki95.com/sv/Special:AbuseFilter/' + data.log_params + '">' + data.log_params + '</a>';
										} else if ( data.log_action === 'hit' ) {
											if ( data.log_params.filter.startsWith( 'global-' ) ) {
												str += globalabusefilterhit;
												str += separator;
												str += '<a href="https://meta.wikimedia.orghttps://wiki95.com/sv/Special:AbuseFilter/' + data.log_params.filter.replace( 'global-', '' ) + '">' + data.log_params.filter.replace( 'global-', '' ) + '</a>';
											} else {
												str += abusefilterhit;
												str += separator;
												str += '<a href="' + data.server_url + 'https://wiki95.com/sv/Special:AbuseFilter/' + data.log_params.filter + '">' + data.log_params.filter + '</a>';
											}
											playSound();
										}
									} else if ( data.log_type === 'thanks' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'thank' ) {
											str += logactionthank;
										}
										str += separator;
										str += title;
									} else if ( data.log_type === 'patrol' ) {
										str += user;
										str += separator;
										if ( data.log_action === 'patrol' ) {
											str += logactionpatrol;
										}
										str += separator;
										str += title;
									}
								}
								if ( data.parsedcomment ) {
									str += separator;
									str += '<span class="gadget-eventstreams-comment">' + data.parsedcomment + '</span>';
								}
								str += '</li>';
								$( '#gadget-eventstreams-list' ).prepend( str );
								lastSavedTimestamp = data.meta.dt;
								savedIds.add( data.meta.id );
							}
						}
					}
				}
			}
		};
		eventSource.onerror = function() {
			setTimeout( function() {
				eventSource.close();
				connect( lastSavedTimestamp );
			}, 1000 );
		};
	}
	if ( v.wgUserLanguage === 'sv' ) {
		settingsbuttontext = 'Inställningar';
		settingsbuttontitle = 'Inställningar för EventStreams';
		projectslabel = 'Välj vilket eller vilka projekt du vill visa, till exempel <code>eswiki</code>, <code>frwiktionary</code> eller <code>dewikivoyage</code>. Separera med radbrytning.';
		excludeuserslabel = 'Exkludera användare (separera med radbrytning)';
		soundfilelabel = 'Ljudfil att spela upp när ett filter utlöses';
		botlabel = 'Visa bothandlingar';
		closetext = 'Stäng';
		error = 'Webbläsaren stöder inte EventSource.';
		diff = 'skillnad';
		typenew = 'Ny sida';
		logtypemove = 'flyttade';
		from = ' från ';
		to = ' till ';
		logactionmoveredir = ' över en omdirigering';
		logtypemovesuppressredirect = ' utan att lämna en omdirigering';
		logactiondelete = 'raderade';
		logactionrestore = 'återställde';
		logactiondeleteredir = 'raderade omdirigeringen';
		logactionrevision = 'ändrade synlighet för';
		logactionevent = 'ändrade synlighet för logghändelse';
		logactioncreate = 'Ny användare';
		logactioncreate2 = 'skapade kontot';
		logactionbyemail = 'lösenordet skickades via e-post';
		logactionblock = 'blockerade';
		logactionreblock = 'ändrade blockeringsinställningar för';
		logactionunblock = 'avblockerade';
		logactionprotect = 'skyddade';
		logactionmodify = 'ändrade skyddsinställningar för';
		logactionunprotect = 'tog bort skydd från';
		logactionrenameuser = 'bytte namn på';
		logactionchange = 'ändrade innehållsmodell för';
		logactionrights = 'ändrade användargrupper för';
		logactionautopromote = 'självbefordrade';
		logactionmerge = 'slog ihop';
		into = 'med';
		abusefiltermodify = 'ändrade filter';
		abusefilterhit = 'utlöste filter';
		globalabusefilterhit = 'utlöste globalt filter';
		logactionthank = 'tackade';
		logactionpatrol = 'patrullerade';
	}
	if ( v.wgPageName === 'Wikipedia:Senaste_ändringar/EventStreams' && v.wgAction === 'view' ) {
		container.empty();
		if ( window.EventSource ) {
			$( '#firstHeading' ).append( '<button type="button" title="' + settingsbuttontitle + '" id="gadget-eventstreams-settingsbutton">' + settingsbuttontext + '</button>' );
			$( '#gadget-eventstreams-settingsbutton' ).click( function() {
				var settingsstr = '<div>';
				settingsstr += '<p><label for="gadget-eventstreams-projects">' + projectslabel + '</label></p>';
				settingsstr += '<textarea id="gadget-eventstreams-projects"></textarea>';
				settingsstr += '<p><label for="gadget-eventstreams-excludeusers">' + excludeuserslabel + '</label></p>';
				settingsstr += '<textarea id="gadget-eventstreams-excludeusers"></textarea>';
				settingsstr += '<p><label for="gadget-eventstreams-soundfile">' + soundfilelabel + '</label></p>';
				settingsstr += '<input id="gadget-eventstreams-soundfile">';
				settingsstr += '<p><label for="gadget-eventstreams-bot">' + botlabel + '</label></p>';
				settingsstr += '<input type="checkbox" id="gadget-eventstreams-bot">';
				settingsstr += '<button type="button" id="gadget-eventstreams-close">' + closetext + '</button>';
				settingsstr += '</div>';

				// Creating and opening a simple dialog window.

				// Subclass Dialog class. Note that the OOjs inheritClass() method extends the parent constructor's prototype and static methods and properties to the child constructor.

				function MyDialog( config ) {
					MyDialog.super.call( this, config );
				}
				var myDialog;
				var windowManager;
				if ( $( '.oo-ui-window-active' ).length === 0 ) {
					OO.inheritClass( MyDialog, OO.ui.Dialog );

					// Specify a title statically (or, alternatively, with data passed to the opening() method).
					MyDialog.static.name = 'gadgeteventstreamsdialog';
					MyDialog.static.title = 'Simple dialog';

					// Customize the initialize() function: This is where to add content to the dialog body and set up event handlers.
					MyDialog.prototype.initialize = function () {
						// Call the parent method
						MyDialog.super.prototype.initialize.call( this );
						// Create and append a layout and some content.
						this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );
						this.content.$element.append( settingsstr );
						this.$body.append( this.content.$element );
						$( '#gadget-eventstreams-projects' ).val( ( getProjects() ).join( '\n' ) );
						$( '#gadget-eventstreams-excludeusers' ).val( ( getExcludedUsers() ).join( '\n' ) );
						$( '#gadget-eventstreams-soundfile' ).val( getSoundFile() );
						if ( getBot() ) {
							$( '#gadget-eventstreams-bot' ).attr( 'checked', 'checked' );
						}
						$( '#gadget-eventstreams-projects' ).on( 'input', function( e ) {
							var projectsinput = $( e.currentTarget ).val().trim();
							if ( projectsinput ) {
								mw.storage.set( projectskey, projectsinput );
							} else {
								mw.storage.remove( projectskey );
							}
						} );
						$( '#gadget-eventstreams-excludeusers' ).on( 'input', function( e ) {
							var excludedusersinput = $( e.currentTarget ).val().trim();
							if ( excludedusersinput ) {
								mw.storage.set( excludeduserskey, excludedusersinput );
							} else {
								mw.storage.remove( excludeduserskey );
							}
						} );
						$( '#gadget-eventstreams-soundfile' ).on( 'input', function( e ) {
							var soundFileInput = $( e.currentTarget ).val().trim();
							if ( soundFileInput ) {
								mw.storage.set( soundfilekey, soundFileInput );
							} else {
								mw.storage.remove( soundfilekey );
							}
						} );
						$( '#gadget-eventstreams-bot' ).on( 'change', function( e ) {
							if ( $( e.currentTarget ).prop( 'checked' ) ) {
								mw.storage.set( botkey, 'true' );
							} else {
								mw.storage.remove( botkey );
							}
						} );
						$( '#gadget-eventstreams-close' ).click( function() {
							myDialog.close();
						} );
					};

					// Use the getTeardownProcess() method to perform actions whenever the dialog is closed.
					// This method provides access to data passed into the window's close() method
					// or the window manager's closeWindow() method.
					MyDialog.prototype.getTeardownProcess = function ( data ) {
						return MyDialog.super.prototype.getTeardownProcess.call( this, data )
						.first( function () {
							// Perform any cleanup as needed
							$( '.oo-ui-windowManager' ).remove();
						}, this );
					};

					// Make the window.
					myDialog = new MyDialog( {
						classes: [
							'gadget-eventstreams-dialog'
						]
					} );

					// Create and append a window manager, which will open and close the window.
					windowManager = new OO.ui.WindowManager();
					$( 'body' ).append( windowManager.$element );

					// Add the window to the window manager using the addWindows() method.
					windowManager.addWindows(  );

					// Open the window!
					windowManager.openWindow( myDialog );
				}
			} );
			container.append( '<ul id="gadget-eventstreams-list"></ul>' );
			connect();
		} else {
			container.append( '<span class="error">' + error + '</span>' );
		}
	}
} );