/*
 *  Copyright (C) 2006-2019  Ronald Blankendaal
 *
 *  This program 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
package org.dbgl.gui.dialog;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.OptionalInt;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.dbgl.constants.Constants;
import org.dbgl.gui.GeneralPurposeDialogs;
import org.dbgl.gui.abstractdialog.SizeControlledTabbedDialog;
import org.dbgl.service.TextService;
import org.dbgl.util.searchengine.WebSearchEngine;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FontDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;


public class SettingsDialog extends SizeControlledTabbedDialog<Boolean> {

	public final static String[] confLocations = {TextService.getInstance().get("dialog.settings.confindbgldir"), TextService.getInstance().get("dialog.settings.confingamedir")};
	public final static String[] confFilenames = {TextService.getInstance().get("dialog.settings.conffilebyid"), TextService.getInstance().get("dialog.settings.conffilebytitle")};

	private final static int EDITABLE_COLUMN = 0;

	private int lastOptionSelection = -1;

	public SettingsDialog(Shell parent) {
		super(parent, "settingsdialog");
		result_ = false;
	}

	@Override
	protected String getDialogTitle() {
		return text_.get("dialog.settings.title");
	}

	@Override
	protected void onShellCreated() {
		Composite generalComposite = createTabWithComposite(text_.get("dialog.settings.tab.general"), new GridLayout());

		Map<String, Locale> locales = getLocales();
		Locale locale = new Locale(settings_.getValue("locale", "language"), settings_.getValue("locale", "country"), settings_.getValue("locale", "variant"));
		String locString = locales.keySet().stream().filter(key -> locales.get(key).equals(locale)).findFirst().orElse(StringUtils.EMPTY);

		Group dosboxGroup = createGroup(generalComposite, text_.get("dialog.settings.dosbox"), 2);
		Button console = createLabelAndCheckButton(dosboxGroup, text_.get("dialog.settings.hidestatuswindow"), settings_.getBooleanValue("dosbox", "hideconsole"));

		Group sendToGroup = createGroup(generalComposite, text_.get("dialog.settings.sendto"), 2);
		Button portEnabled = createLabelAndCheckButton(sendToGroup, text_.get("dialog.settings.enableport"), settings_.getBooleanValue("communication", "port_enabled"));
		Text port = createLabelAndText(sendToGroup, text_.get("dialog.settings.port"), settings_.getValue("communication", "port"));
		port.setEnabled(portEnabled.getSelection());
		portEnabled.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				port.setEnabled(portEnabled.getSelection());
			}
		});

		Group profileDefGroup = createGroup(generalComposite, text_.get("dialog.settings.profiledefaults"), 3);
		Combo confLocation = createLabelAndCombo(profileDefGroup, text_.get("dialog.settings.configfile"), confLocations, 10, settings_.getIntValue("profiledefaults", "confpath"));
		Combo confFilename = createCombo(profileDefGroup, confFilenames, 10, settings_.getIntValue("profiledefaults", "conffile"));

		Group i18nGroup = createGroup(generalComposite, text_.get("dialog.settings.i18n"), 2);
		Combo localeCombo = createLabelAndCombo(i18nGroup, text_.get("dialog.settings.languagecountry"), locales.keySet().toArray(new String[0]), 20);
		localeCombo.setText(locString);

		Composite profileTableComposite = createTabWithComposite(text_.get("dialog.settings.tab.profiletable"), new GridLayout());

		List<Integer> allColumnIds = getColumnIds();

		Group visColumnsGroup = createGroup(profileTableComposite, new GridData(SWT.FILL, SWT.FILL, true, true), text_.get("dialog.settings.visiblecolunms"), new FillLayout());
		Table visibleColumnsTable = new Table(visColumnsGroup, SWT.FULL_SELECTION | SWT.BORDER | SWT.CHECK);
		visibleColumnsTable.setLinesVisible(true);
		TableColumn column1 = new TableColumn(visibleColumnsTable, SWT.NONE);
		column1.setWidth(350);
		TableItem[] visibleColumns = new TableItem[MainWindow.columnNames_.length];
		for (int i = 0; i < MainWindow.columnNames_.length; i++) {
			visibleColumns[i] = new TableItem(visibleColumnsTable, SWT.BORDER);
			visibleColumns[i].setText(MainWindow.columnNames_[allColumnIds.get(i)]);
			visibleColumns[i].setChecked(settings_.getBooleanValue("gui", "column" + (allColumnIds.get(i) + 1) + "visible"));
		}

		TableEditor editor = new TableEditor(visibleColumnsTable);
		editor.horizontalAlignment = SWT.LEFT;
		editor.grabHorizontal = true;
		editor.minimumWidth = 50;

		visibleColumnsTable.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				// Clean up any previous editor control
				Control oldEditor = editor.getEditor();
				if (oldEditor != null) {
					oldEditor.dispose();
				}

				// Identify the selected row
				TableItem item = (TableItem)event.item;
				if (item == null) {
					return;
				}
				int selIdx = item.getParent().getSelectionIndex();
				if (selIdx == -1)
					return;
				int idx = allColumnIds.get(selIdx);
				if ((idx >= Constants.RO_COLUMN_NAMES && idx < (Constants.RO_COLUMN_NAMES + Constants.EDIT_COLUMN_NAMES_1))
						|| (idx >= Constants.RO_COLUMN_NAMES + Constants.EDIT_COLUMN_NAMES_1 + Constants.STATS_COLUMN_NAMES
								&& idx < (Constants.RO_COLUMN_NAMES + Constants.EDIT_COLUMN_NAMES_1 + Constants.STATS_COLUMN_NAMES + Constants.EDIT_COLUMN_NAMES_2))) {
					// The control that will be the editor must be a child of the table
					Text newEditor = createText(visibleColumnsTable, item.getText(EDITABLE_COLUMN));
					newEditor.addModifyListener(new ModifyListener() {
						public void modifyText(ModifyEvent mEvent) {
							Text text = (Text)editor.getEditor();
							editor.getItem().setText(EDITABLE_COLUMN, text.getText());
						}
					});
					newEditor.selectAll();
					newEditor.setFocus();
					editor.setEditor(newEditor, item, EDITABLE_COLUMN);
				}
			}
		});

		Group addProfGroup = createGroup(profileTableComposite, new GridData(SWT.FILL, SWT.FILL, true, false), text_.get("dialog.settings.addeditduplicateprofile"), 2);
		Button autosort = createLabelAndCheckButton(addProfGroup, text_.get("dialog.settings.autosort"), settings_.getBooleanValue("gui", "autosortonupdate"));

		Composite dynamicOptionsComposite = createTabWithComposite(text_.get("dialog.settings.tab.dynamicoptions"), 2);

		createLabel(dynamicOptionsComposite, text_.get("dialog.settings.options"));
		createLabel(dynamicOptionsComposite, text_.get("dialog.settings.values"));
		org.eclipse.swt.widgets.List optionsList = new org.eclipse.swt.widgets.List(dynamicOptionsComposite, SWT.V_SCROLL | SWT.BORDER);
		optionsList.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		Text values = createTextarea(dynamicOptionsComposite, false);

		Map<String, String> optionsMap = new LinkedHashMap<>();
		for (String s: settings_.getProfileSectionItemNames()) {
			optionsMap.put(s, settings_.getMultilineValue("profile", s, values.getLineDelimiter()));
			optionsList.add(s);
		}

		optionsList.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				updateOptionsMap(optionsMap, optionsList, lastOptionSelection, values);
				lastOptionSelection = optionsList.getSelectionIndex();
				if (lastOptionSelection != -1) {
					values.setText(optionsMap.get(optionsList.getItem(lastOptionSelection)));
				}
			}
		});

		Composite guiComposite = createTabWithComposite(text_.get("dialog.settings.tab.gui"), 2);

		Font notesFont = stringToFont(shell_.getDisplay(), settings_.getValues("gui", "notesfont"), port.getFont());

		Group screenshots = createGroup(guiComposite, new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1), text_.get("dialog.settings.screenshots"), 3);
		Scale screenshotsHeight = createLabelAndScale(screenshots, text_.get("dialog.settings.height"), false, new GridData(SWT.FILL, SWT.FILL, true, false),
			settings_.getIntValue("gui", "screenshotsheight"), 50, 750, 25, 100);
		Label heightValue = createLabel(screenshots, screenshotsHeight.getSelection() + text_.get("dialog.settings.px"));
		screenshotsHeight.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent evt) {
				heightValue.setText(screenshotsHeight.getSelection() + text_.get("dialog.settings.px"));
				heightValue.pack();
			}
		});
		Button displayFilename = createLabelAndCheckButton(screenshots, text_.get("dialog.settings.screenshotsfilename"), 2, settings_.getBooleanValue("gui", "screenshotsfilename"));

		Group screenshotsColumn = createGroup(guiComposite, new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1), text_.get("dialog.settings.screenshotscolumn"), 3);
		Scale screenshotsColumnHeight = createLabelAndScale(screenshotsColumn, text_.get("dialog.settings.height"), false, new GridData(SWT.FILL, SWT.FILL, true, false),
			settings_.getIntValue("gui", "screenshotscolumnheight"), 16, 200, 4, 16);
		Label columnHeightValue = createLabel(screenshotsColumn, screenshotsColumnHeight.getSelection() + text_.get("dialog.settings.px"));
		screenshotsColumnHeight.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent evt) {
				columnHeightValue.setText(screenshotsColumnHeight.getSelection() + text_.get("dialog.settings.px"));
				columnHeightValue.pack();
			}
		});
		Button stretch = createLabelAndCheckButton(screenshotsColumn, text_.get("dialog.settings.screenshotscolumnstretch"), 2, settings_.getBooleanValue("gui", "screenshotscolumnstretch"));
		Button keepAspectRatio = createLabelAndCheckButton(screenshotsColumn, text_.get("dialog.settings.screenshotscolumnkeepaspectratio"), 2,
			settings_.getBooleanValue("gui", "screenshotscolumnkeepaspectratio"));
		keepAspectRatio.setEnabled(stretch.getSelection());
		stretch.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				keepAspectRatio.setEnabled(stretch.getSelection());
			}
		});

		Group buttonsGroup = createGroup(guiComposite, new GridData(SWT.FILL, SWT.CENTER, true, false), text_.get("dialog.settings.buttons"), 2);
		Combo buttonDisplay = createLabelAndCombo(buttonsGroup, text_.get("dialog.settings.display"),
			new String[] {text_.get("dialog.settings.displaybuttonimageandtext"), text_.get("dialog.settings.displaybuttontextonly"), text_.get("dialog.settings.displaybuttonimageonly")}, 10,
			settings_.getIntValue("gui", "buttondisplay"));

		Group notesGroup = createGroup(guiComposite, new GridData(SWT.FILL, SWT.CENTER, true, false), text_.get("dialog.profile.notes"), 2);
		Button fontButton = createLabelAndButton(notesGroup, text_.get("dialog.settings.font"), notesFont.getFontData()[0].getName(), new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				Button fontButton = (Button)e.getSource();
				FontDialog fd = new FontDialog(shell_, SWT.NONE);
				fd.setFontList(fontButton.getFont().getFontData());
				FontData newFont = fd.open();
				if (newFont != null) {
					fontButton.setText(newFont.getName());
					fontButton.setFont(new Font(shell_.getDisplay(), newFont));
					notesGroup.setSize(notesGroup.computeSize(SWT.DEFAULT, SWT.DEFAULT));
					guiComposite.layout();
				}
			}
		});
		fontButton.setFont(notesFont);

		Composite enginesComposite = createTabWithComposite(text_.get("dialog.settings.tab.engines"), new FillLayout());

		int nrOfEngines = Constants.WEBSEARCH_ENGINES.size();
		Button[] setTitle = new Button[nrOfEngines];
		Button[] setDev = new Button[nrOfEngines];
		Button[] setPub = new Button[nrOfEngines];
		Button[] setYear = new Button[nrOfEngines];
		Button[] setGenre = new Button[nrOfEngines];
		Button[] setLink = new Button[nrOfEngines];
		Button[] setRank = new Button[nrOfEngines];
		Button[] setDescr = new Button[nrOfEngines];
		Button[] allRegionsCoverArt = new Button[nrOfEngines];
		Button[] chooseCoverArt = new Button[nrOfEngines];
		Button[] chooseScreenshot = new Button[nrOfEngines];
		Spinner[] maxCoverArt = new Spinner[nrOfEngines];
		Spinner[] maxScreenshots = new Spinner[nrOfEngines];
		Text[] platformFilterValues = new Text[nrOfEngines];

		TabFolder enginesTabFolder = new TabFolder(enginesComposite, SWT.NONE);

		for (int i = 0; i < nrOfEngines; i++) {
			WebSearchEngine engine = Constants.WEBSEARCH_ENGINES.get(i);

			Composite engineComposite = createTabWithComposite(enginesTabFolder, text_.get("dialog.settings.tab." + engine.getSimpleName()), new FillLayout());

			Group consultGroup = createGroup(engineComposite, text_.get("dialog.settings.consult", new String[] {engine.getName()}), 2);
			setTitle[i] = createLabelAndCheckButton(consultGroup, text_.get("dialog.settings.settitle"), settings_.getBooleanValue(engine.getSimpleName(), "set_title"));
			setDev[i] = createLabelAndCheckButton(consultGroup, text_.get("dialog.settings.setdeveloper"), settings_.getBooleanValue(engine.getSimpleName(), "set_developer"));
			if (engine.getSimpleName().equals("mobygames") || engine.getSimpleName().equals("thegamesdb")) {
				setPub[i] = createLabelAndCheckButton(consultGroup, text_.get("dialog.settings.setpublisher"), settings_.getBooleanValue(engine.getSimpleName(), "set_publisher"));
			}
			setYear[i] = createLabelAndCheckButton(consultGroup, text_.get("dialog.settings.setyear"), settings_.getBooleanValue(engine.getSimpleName(), "set_year"));
			setGenre[i] = createLabelAndCheckButton(consultGroup, text_.get("dialog.settings.setgenre"), settings_.getBooleanValue(engine.getSimpleName(), "set_genre"));
			setLink[i] = createLabelAndCheckButton(consultGroup, text_.get("dialog.settings.setlink", new String[] {engine.getName()}), settings_.getBooleanValue(engine.getSimpleName(), "set_link"));
			setRank[i] = createLabelAndCheckButton(consultGroup, text_.get("dialog.settings.setrank", new Object[] {MainWindow.columnNames_[Constants.RO_COLUMN_NAMES + 8]}),
				settings_.getBooleanValue(engine.getSimpleName(), "set_rank"));
			if (engine.getSimpleName().equals("mobygames") || engine.getSimpleName().equals("thegamesdb")) {
				setDescr[i] = createLabelAndCheckButton(consultGroup, text_.get("dialog.settings.setdescription"), settings_.getBooleanValue(engine.getSimpleName(), "set_description"));
			}
			if (engine.getSimpleName().equals("mobygames") || engine.getSimpleName().equals("thegamesdb")) {
				createLabel(consultGroup, text_.get("dialog.settings.choosecoverart"));

				Composite comp = createInnerComposite(consultGroup, null, 3);
				chooseCoverArt[i] = createCheckButton(comp, settings_.getBooleanValue(engine.getSimpleName(), "choose_coverart"));

				if (engine.getSimpleName().equals("mobygames")) {
					GridData gd = new GridData();
					gd.horizontalIndent = 40;
					createLabel(comp, text_.get("dialog.settings.allregionscoverart")).setLayoutData(gd);
					allRegionsCoverArt[i] = createCheckButton(comp, settings_.getBooleanValue(engine.getSimpleName(), "force_all_regions_coverart"));
				}
			}
			chooseScreenshot[i] = createLabelAndCheckButton(consultGroup, text_.get("dialog.settings.choosescreenshot"), settings_.getBooleanValue(engine.getSimpleName(), "choose_screenshot"));
			if (engine.getSimpleName().equals("mobygames") || engine.getSimpleName().equals("thegamesdb")) {
				maxCoverArt[i] = createLabelAndSpinner(consultGroup, text_.get("dialog.settings.multieditmaxcoverart"), settings_.getIntValue(engine.getSimpleName(), "multi_max_coverart"));
			}
			maxScreenshots[i] = createLabelAndSpinner(consultGroup, text_.get("dialog.settings.multieditmaxscreenshot"), settings_.getIntValue(engine.getSimpleName(), "multi_max_screenshot"));
			createLabel(consultGroup, text_.get("dialog.settings.platformfilter"));
			if (engine.getSimpleName().equals("mobygames") || engine.getSimpleName().equals("pouet")) {
				platformFilterValues[i] = createTextarea(consultGroup, false, false, 1, 1, settings_.getMultilineValue(engine.getSimpleName(), "platform_filter", values.getLineDelimiter()));
			} else {
				platformFilterValues[i] = createText(consultGroup, SWT.BORDER, new GridData(SWT.FILL, SWT.FILL, true, false), settings_.getValue(engine.getSimpleName(), "platform_filter"), null);
			}
		}

		Composite envComposite = createTabWithComposite(text_.get("dialog.settings.tab.environment"), new FillLayout());

		Group envGroup = createGroup(envComposite, text_.get("dialog.settings.environment"), 2);
		Button enableEnv = createLabelAndCheckButton(envGroup, text_.get("dialog.settings.enableenvironment"), settings_.getBooleanValue("environment", "use"));
		Text envValues = createLabelAndTextarea(envGroup, text_.get("dialog.settings.environmentvariables"), false, settings_.getMultilineValue("environment", "value", values.getLineDelimiter()));
		envValues.setEnabled(enableEnv.getSelection());
		enableEnv.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				envValues.setEnabled(enableEnv.getSelection());
			}
		});

		createOkCancelButtons(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				if (!isValid(visibleColumnsTable, visibleColumns, getTabItemByComposite(profileTableComposite))) {
					return;
				}

				boolean changedVisColumns = haveColumnsBeenChanged();
				if (changedVisColumns)
					updateColumnSettings(allColumnIds, visibleColumns);

				settings_.setBooleanValue("dosbox", "hideconsole", console.getSelection());
				settings_.setBooleanValue("communication", "port_enabled", portEnabled.getSelection());
				settings_.setValue("communication", "port", port.getText());
				settings_.setIntValue("profiledefaults", "confpath", confLocation.getSelectionIndex());
				settings_.setIntValue("profiledefaults", "conffile", confFilename.getSelectionIndex());
				settings_.setValue("locale", "language", locales.get(localeCombo.getText()).getLanguage());
				settings_.setValue("locale", "country", locales.get(localeCombo.getText()).getCountry());
				settings_.setValue("locale", "variant", locales.get(localeCombo.getText()).getVariant());
				for (int i = 0; i < MainWindow.columnNames_.length; i++) {
					settings_.setBooleanValue("gui", "column" + (i + 1) + "visible", visibleColumns[allColumnIds.indexOf(i)].getChecked());
				}
				settings_.setBooleanValue("gui", "autosortonupdate", autosort.getSelection());
				for (int i = 0; i < Constants.EDIT_COLUMN_NAMES_1; i++) {
					settings_.setValue("gui", "custom" + (i + 1), visibleColumns[allColumnIds.indexOf(i + Constants.RO_COLUMN_NAMES)].getText());
				}
				for (int i = 0; i < Constants.EDIT_COLUMN_NAMES_2; i++) {
					settings_.setValue("gui", "custom" + (i + Constants.EDIT_COLUMN_NAMES_1 + 1),
						visibleColumns[allColumnIds.indexOf(i + Constants.RO_COLUMN_NAMES + Constants.EDIT_COLUMN_NAMES_1 + Constants.STATS_COLUMN_NAMES)].getText());
				}
				settings_.setIntValue("gui", "screenshotsheight", screenshotsHeight.getSelection());
				settings_.setBooleanValue("gui", "screenshotsfilename", displayFilename.getSelection());
				settings_.setIntValue("gui", "screenshotscolumnheight", screenshotsColumnHeight.getSelection());
				settings_.setBooleanValue("gui", "screenshotscolumnstretch", stretch.getSelection());
				settings_.setBooleanValue("gui", "screenshotscolumnkeepaspectratio", keepAspectRatio.getSelection());

				Rectangle rec = shell_.getBounds();
				settings_.setIntValue("gui", "settingsdialog_width", rec.width);
				settings_.setIntValue("gui", "settingsdialog_height", rec.height);
				settings_.setIntValue("gui", "buttondisplay", buttonDisplay.getSelectionIndex());
				settings_.setMultilineValue("gui", "notesfont", fontToString(shell_.getDisplay(), fontButton.getFont()), "|");

				for (int i = 0; i < nrOfEngines; i++) {
					WebSearchEngine engine = Constants.WEBSEARCH_ENGINES.get(i);
					settings_.setBooleanValue(engine.getSimpleName(), "set_title", setTitle[i].getSelection());
					settings_.setBooleanValue(engine.getSimpleName(), "set_developer", setDev[i].getSelection());
					if (engine.getSimpleName().equals("mobygames") || engine.getSimpleName().equals("thegamesdb")) {
						settings_.setBooleanValue(engine.getSimpleName(), "set_publisher", setPub[i].getSelection());
						settings_.setBooleanValue(engine.getSimpleName(), "set_description", setDescr[i].getSelection());
					}
					settings_.setBooleanValue(engine.getSimpleName(), "set_year", setYear[i].getSelection());
					settings_.setBooleanValue(engine.getSimpleName(), "set_genre", setGenre[i].getSelection());
					settings_.setBooleanValue(engine.getSimpleName(), "set_link", setLink[i].getSelection());
					settings_.setBooleanValue(engine.getSimpleName(), "set_rank", setRank[i].getSelection());
					if (engine.getSimpleName().equals("mobygames")) {
						settings_.setBooleanValue(engine.getSimpleName(), "force_all_regions_coverart", allRegionsCoverArt[i].getSelection());
					}
					if (engine.getSimpleName().equals("mobygames") || engine.getSimpleName().equals("thegamesdb")) {
						settings_.setBooleanValue(engine.getSimpleName(), "choose_coverart", chooseCoverArt[i].getSelection());
						settings_.setIntValue(engine.getSimpleName(), "multi_max_coverart", maxCoverArt[i].getSelection());
					}
					if (engine.getSimpleName().equals("mobygames") || engine.getSimpleName().equals("pouet") || engine.getSimpleName().equals("thegamesdb")) {
						settings_.setBooleanValue(engine.getSimpleName(), "choose_screenshot", chooseScreenshot[i].getSelection());
						settings_.setIntValue(engine.getSimpleName(), "multi_max_screenshot", maxScreenshots[i].getSelection());
					}
					if (engine.getSimpleName().equals("mobygames") || engine.getSimpleName().equals("pouet")) {
						settings_.setMultilineValue(engine.getSimpleName(), "platform_filter", platformFilterValues[i].getText(), platformFilterValues[i].getLineDelimiter());
					} else {
						settings_.setValue(engine.getSimpleName(), "platform_filter", platformFilterValues[i].getText());
					}
				}

				settings_.setBooleanValue("environment", "use", enableEnv.getSelection());
				settings_.setMultilineValue("environment", "value", envValues.getText(), envValues.getLineDelimiter());

				updateOptionsMap(optionsMap, optionsList, lastOptionSelection, values);
				for (Map.Entry<String, String> entry: optionsMap.entrySet())
					settings_.setMultilineValue("profile", entry.getKey(), entry.getValue(), values.getLineDelimiter());

				result_ = changedVisColumns;
				shell_.close();
			}

			private boolean haveColumnsBeenChanged() {
				for (int i = 0; i < MainWindow.columnNames_.length; i++)
					if ((settings_.getBooleanValue("gui", "column" + (allColumnIds.get(i) + 1) + "visible") != visibleColumns[i].getChecked())
							|| !MainWindow.columnNames_[allColumnIds.get(i)].equals(visibleColumns[i].getText()))
						return true;
				return false;
			}
		});
	}

	private void updateOptionsMap(Map<String, String> optionsMap, org.eclipse.swt.widgets.List options, int lastOptionSelection, Text values) {
		if (lastOptionSelection != -1)
			optionsMap.put(options.getItem(lastOptionSelection), values.getText());
	}

	private void updateColumnSettings(List<Integer> allColumnIds, TableItem[] visibleColumns) {
		int[] sort = settings_.getIntValues("gui", "sortcolumn");
		boolean[] ascs = settings_.getBooleanValues("gui", "sortascending");
		List<Integer> sortColumnIDs = new ArrayList<>(sort.length);
		List<Boolean> sortColumnAscs = new ArrayList<>(sort.length);

		for (int i = 0; i < sort.length; i++) {
			if (visibleColumns[allColumnIds.indexOf(sort[i])].getChecked()) {
				sortColumnIDs.add(sort[i]);
				sortColumnAscs.add(ascs[i]);
			}
		}
		if (sortColumnIDs.isEmpty()) {
			OptionalInt firstVisibleColumn = IntStream.range(0, visibleColumns.length).filter(i -> visibleColumns[i].getChecked()).findFirst();
			if (firstVisibleColumn.isPresent()) {
				sortColumnIDs.add(allColumnIds.get(firstVisibleColumn.getAsInt()));
				sortColumnAscs.add(true);
			}
		}

		settings_.setIntValues("gui", "sortcolumn", ArrayUtils.toPrimitive(sortColumnIDs.toArray(new Integer[0])));
		settings_.setBooleanValues("gui", "sortascending", ArrayUtils.toPrimitive(sortColumnAscs.toArray(new Boolean[0])));

		List<Integer> visColumns = new ArrayList<>();
		for (int i = 0; i < MainWindow.columnNames_.length; i++)
			if (visibleColumns[i].getChecked())
				visColumns.add(allColumnIds.get(i));

		List<Integer> orderedVisColumns = new ArrayList<>(visColumns);
		Collections.sort(orderedVisColumns);

		List<Integer> colOrder = new ArrayList<>();
		for (int id: visColumns)
			colOrder.add(orderedVisColumns.indexOf(id));

		settings_.setValue("gui", "columnorder", StringUtils.join(colOrder, ' '));
	}

	private SortedMap<String, Locale> getLocales() {
		List<String> supportedLanguages = new ArrayList<>(Constants.SUPPORTED_LANGUAGES);
		File[] files = new File("./plugins/i18n").listFiles();
		if (files != null) {
			for (File file: files) {
				String name = file.getName();
				if (name.startsWith("MessagesBundle_") && name.endsWith(".properties")) {
					String code = name.substring("MessagesBundle_".length(), name.indexOf(".properties"));
					if (code.length() > 0) {
						supportedLanguages.add(code);
					}
				}
			}
		}

		SortedMap<String, Locale> allLocales = new TreeMap<>();
		for (Locale loc: Locale.getAvailableLocales())
			allLocales.put(loc.toString(), loc);

		SortedMap<String, Locale> locales = new TreeMap<>();

		for (String lang: supportedLanguages) {
			Locale loc = allLocales.get(lang);
			String variant = null;
			if (loc == null && StringUtils.countMatches(lang, "_") == 2) {
				String langWithoutVariant = StringUtils.removeEnd(StringUtils.substringBeforeLast(lang, "_"), "_");
				variant = StringUtils.substringAfterLast(lang, "_");
				loc = allLocales.get(langWithoutVariant);
			}
			if (loc != null) {
				StringBuffer s = new StringBuffer(loc.getDisplayLanguage());
				s.append(" [").append(loc.getDisplayLanguage(loc)).append("]");
				if (loc.getCountry().length() > 0)
					s.append(" - ").append(loc.getDisplayCountry()).append(" [").append(loc.getDisplayCountry(loc)).append("]");
				if (variant != null) {
					s.append(" (").append(variant).append(')');
					loc = new Locale(loc.getLanguage(), loc.getCountry(), variant);
				}
				locales.put(s.toString(), loc);
			}
		}

		return locales;
	}

	private List<Integer> getColumnIds() {
		List<Integer> visibleColumnIds = new ArrayList<>();
		for (int i = 0; i < MainWindow.columnNames_.length; i++)
			if (settings_.getBooleanValue("gui", "column" + (i + 1) + "visible"))
				visibleColumnIds.add(i);
		List<Integer> orderedVisibleColumnIds = new ArrayList<>();
		int[] columnOrder = settings_.getIntValues("gui", "columnorder");
		for (int element: columnOrder)
			orderedVisibleColumnIds.add(visibleColumnIds.get(element));
		List<Integer> remainingColumnIDs = new ArrayList<>();
		for (int i = 0; i < MainWindow.columnNames_.length; i++)
			if (!orderedVisibleColumnIds.contains(i))
				remainingColumnIDs.add(i);
		List<Integer> allColumnIds = new ArrayList<>(orderedVisibleColumnIds);
		allColumnIds.addAll(remainingColumnIDs);
		return allColumnIds;
	}

	private boolean isValid(Table visibleColumnsTable, TableItem[] visibleColumns, TabItem columnsTabItem) {
		GeneralPurposeDialogs.initErrorDialog();
		if (Stream.of(visibleColumns).noneMatch(x -> x.getChecked())) {
			GeneralPurposeDialogs.addError(text_.get("dialog.settings.required.onevisiblecolumn"), visibleColumnsTable, columnsTabItem);
		}
		return !GeneralPurposeDialogs.displayErrorDialog(shell_);
	}
}
