/*
 *  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.wizard;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.dbgl.constants.Constants;
import org.dbgl.gui.GeneralPurposeDialogs;
import org.dbgl.gui.abstractdialog.EditConfigurableDialog;
import org.dbgl.gui.abstractdialog.WizardDialog;
import org.dbgl.gui.controls.BrowseButton;
import org.dbgl.gui.controls.BrowseButton.BrowseType;
import org.dbgl.gui.controls.BrowseButton.CanonicalType;
import org.dbgl.gui.controls.SearchEngineSelector;
import org.dbgl.gui.dialog.BrowseSearchEngineDialog;
import org.dbgl.gui.dialog.LoadSharedConfDialog;
import org.dbgl.gui.dialog.LoadSharedConfDialog.SharedConfLoading;
import org.dbgl.model.FileLocation;
import org.dbgl.model.Link;
import org.dbgl.model.WebProfile;
import org.dbgl.model.aggregate.DosboxVersion;
import org.dbgl.model.aggregate.Profile;
import org.dbgl.model.aggregate.Template;
import org.dbgl.model.conf.Configuration;
import org.dbgl.model.entity.SharedConf;
import org.dbgl.model.factory.ProfileFactory;
import org.dbgl.model.repository.DosboxVersionRepository;
import org.dbgl.model.repository.ProfileRepository;
import org.dbgl.model.repository.TemplateRepository;
import org.dbgl.service.FileLocationService;
import org.dbgl.service.ImageService;
import org.dbgl.util.DosGameUtils;
import org.dbgl.util.ExecuteUtils;
import org.dbgl.util.ExecuteUtils.ProfileRunMode;
import org.dbgl.util.FilesUtils;
import org.dbgl.util.StringRelatedUtils;
import org.dbgl.util.iso.ISO9660FileSystem;
import org.dbgl.util.searchengine.WebSearchEngine;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
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.Group;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;


public class AddGameWizardDialog extends WizardDialog<Profile> {

	private List<DosboxVersion> dbversionsList_;
	private List<Template> templatesList_;
	private Profile profile_;

	private Text title_, mainText_, setupText_, installExe_, installParameters_, patchExe_, patchParameters_, dstDirectory_, imagesDstDirectory_;
	private SearchEngineSelector engineSelector_;
	private ToolItem loadSharedConfButton_;
	private Combo main_, setup_, machine_, core_, cycles_, mapper_;
	private Button moveImages_, btnPreinstalledGame_, btnGameNeedsToBeInstalled_, btnInstallManual_, btnPatchManual_;
	private org.eclipse.swt.widgets.List mountingpoints_, installedFilesList_, orgImagesList_;
	private List<FileLocation> orgImages_;
	private List<FileLocation> installedFiles_;

	public AddGameWizardDialog(Shell parent) {
		super(parent, "addgamewizard");
	}

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

	@Override
	protected boolean prepare() {
		try {
			dbversionsList_ = new DosboxVersionRepository().listAll();
			templatesList_ = new TemplateRepository().listAll(dbversionsList_);

			StringBuffer warningsLog = new StringBuffer();

			DosboxVersion dbVersion = DosboxVersionRepository.findDefault(dbversionsList_);
			warningsLog.append(dbVersion.resetAndLoadConfiguration());

			Template template = TemplateRepository.findDefault(templatesList_);
			if (template != null)
				warningsLog.append(template.resetAndLoadConfiguration());

			profile_ = ProfileFactory.create(dbVersion, template);

			if (StringUtils.isNotBlank(warningsLog))
				GeneralPurposeDialogs.warningMessage(getParent(), warningsLog.toString());

			return true;
		} catch (Exception e) {
			GeneralPurposeDialogs.warningMessage(getParent(), e);
			return false;
		}
	}

	@Override
	protected void onShellCreated() {
		Group step0Group = createGroup(shell_, text_.get("dialog.addgamewizard.step1"), 3);
		title_ = createLabelAndText(step0Group, text_.get("dialog.profile.title"));

		ToolBar toolBar = new ToolBar(step0Group, SWT.FLAT);
		engineSelector_ = new SearchEngineSelector(toolBar, true);
		engineSelector_.addToggleSelectionListener(settings_.getBooleanValue("addgamewizard", "consultsearchengine"));

		boolean loadSharedConfEnabledByDefault = settings_.getBooleanValue("addgamewizard", "consultdbconfws");
		loadSharedConfButton_ = createImageToolItem(toolBar, SWT.PUSH,
			loadSharedConfEnabledByDefault ? ImageService.getResourceImage(shell_.getDisplay(), ImageService.IMG_SHARE)
					: ImageService.createDisabledImage(ImageService.getResourceImage(shell_.getDisplay(), ImageService.IMG_SHARE)),
			text_.get("button.consultconfsearchengine", new String[] {Constants.DBCONFWS}), new SelectionAdapter() {
				public void widgetSelected(SelectionEvent event) {
					if ((Boolean)loadSharedConfButton_.getData("selected")) {
						loadSharedConfButton_.setImage(ImageService.createDisabledImage(ImageService.getResourceImage(shell_.getDisplay(), ImageService.IMG_SHARE)));
						loadSharedConfButton_.setData("selected", false);
						settings_.setBooleanValue("addgamewizard", "consultdbconfws", false);
					} else {
						loadSharedConfButton_.setImage(ImageService.getResourceImage(shell_.getDisplay(), ImageService.IMG_SHARE));
						loadSharedConfButton_.setData("selected", true);
						settings_.setBooleanValue("addgamewizard", "consultdbconfws", true);
					}
				}
			});
		loadSharedConfButton_.setData("selected", loadSharedConfEnabledByDefault);

		createLabel(step0Group, 3, 1);
		createLabel(step0Group, SWT.NONE, new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 3, 1), text_.get("dialog.addgamewizard.thisgame"));
		boolean requiresInstallation = settings_.getBooleanValue("addgamewizard", "requiresinstallation");
		btnPreinstalledGame_ = createRadioButton(step0Group, text_.get("dialog.addgamewizard.preinstalled"), 3, !requiresInstallation);
		btnGameNeedsToBeInstalled_ = createRadioButton(step0Group, text_.get("dialog.addgamewizard.notyetinstalled"), 3, requiresInstallation);
		SelectionAdapter adapter = new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				settings_.setBooleanValue("addgamewizard", "requiresinstallation", event.widget == btnGameNeedsToBeInstalled_);
			}
		};
		btnPreinstalledGame_.addSelectionListener(adapter);
		btnGameNeedsToBeInstalled_.addSelectionListener(adapter);
		addStep(step0Group);

		Group step1Group = createGroup(shell_, text_.get("dialog.addgamewizard.step2"), 3);
		installExe_ = createLabelAndText(step1Group, text_.get("dialog.addgamewizard.installexe"));
		installExe_.addVerifyListener(new VerifyListener() {
			public void verifyText(VerifyEvent event) {
				if (event.text.length() > 1) {
					profile_.addRequiredMount(false, event.text, true);
					mountingpoints_.setItems(profile_.getMountStringsForUI());
				}
			}
		});
		new BrowseButton(step1Group).connect(shell_, installExe_, null, BrowseType.FILE, CanonicalType.INSTALLER, false, null);
		installParameters_ = createLabelAndText(step1Group, text_.get("dialog.profile.mainparameters"), 2);
		btnInstallManual_ = createLabelAndCheckButton(step1Group, text_.get("dialog.addgamewizard.manualmode"), 2, text_.get("dialog.addgamewizard.manualmodeinfo"));
		createLabel(step1Group, 3, 1);
		Group mountGroup = createGroup(step1Group, new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1), text_.get("dialog.template.mountingoverview"), 2);
		mountingpoints_ = createList(mountGroup, 1, 3);
		mountingpoints_.addMouseListener(new MouseAdapter() {
			public void mouseDoubleClick(MouseEvent event) {
				if (mountingpoints_.getSelectionIndex() == -1) {
					EditConfigurableDialog.doAddMount(shell_, false, mountingpoints_, profile_);
				} else {
					EditConfigurableDialog.doEditMount(shell_, mountingpoints_, profile_);
				}
			}
		});
		createButton(mountGroup, text_.get("dialog.template.mount.add"), new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				EditConfigurableDialog.doAddMount(shell_, false, mountingpoints_, profile_);
			}
		});
		createButton(mountGroup, text_.get("dialog.template.mount.edit"), new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				EditConfigurableDialog.doEditMount(shell_, mountingpoints_, profile_);
			}
		});
		createButton(mountGroup, text_.get("dialog.template.mount.remove"), new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				EditConfigurableDialog.doRemoveMount(mountingpoints_, profile_);
			}
		});
		Group associationGroup = createGroup(step1Group, new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1), text_.get("dialog.template.association"), 2);
		int dbversionIndex = DosboxVersionRepository.indexOf(dbversionsList_, profile_.getDosboxVersion());
		Combo dbversion = createLabelAndCombo(associationGroup, text_.get("dialog.template.dosboxversion"), dbversionsList_.stream().map(x -> x.getTitle()).toArray(String[]::new), 20, dbversionIndex);
		dbversion.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
		dbversion.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				try {
					String warningsLog = profile_.switchToDosboxVersion(dbversionsList_.get(dbversion.getSelectionIndex()));

					resetMounts();

					if (StringUtils.isNotEmpty(warningsLog)) {
						GeneralPurposeDialogs.warningMessage(getParent(), warningsLog.toString());
					}
				} catch (IOException e) {
					GeneralPurposeDialogs.warningMessage(getParent(), e);
				}
			}
		});
		addStep(step1Group);

		Group step2Group = createGroup(shell_, text_.get("dialog.addgamewizard.step3"), 3);
		patchExe_ = createLabelAndText(step2Group, text_.get("dialog.addgamewizard.patcherexe"));
		new BrowseButton(step2Group).connect(shell_, patchExe_, null, BrowseType.FILE, CanonicalType.INSTALLER, false, null);
		patchParameters_ = createLabelAndText(step2Group, text_.get("dialog.profile.mainparameters"), 2);
		btnPatchManual_ = createLabelAndCheckButton(step2Group, text_.get("dialog.addgamewizard.manualmode"), 2, text_.get("dialog.addgamewizard.manualpatchmodeinfo"));
		addStep(step2Group);

		Group step3Group = createGroup(shell_, text_.get("dialog.addgamewizard.step4"), 2);
		main_ = createLabelAndWideCombo(step3Group, text_.get("dialog.profile.mainexe"));
		setup_ = createLabelAndWideCombo(step3Group, text_.get("dialog.profile.setupexe"));
		addStep(step3Group);

		Group step4Group = createGroup(shell_, text_.get("dialog.addgamewizard.step4"), 3);
		mainText_ = createLabelAndText(step4Group, text_.get("dialog.profile.mainexe"));
		new BrowseButton(step4Group).connect(shell_, mainText_, null, BrowseType.FILE, CanonicalType.EXE, false, null);
		setupText_ = createLabelAndText(step4Group, text_.get("dialog.profile.setupexe"));
		new BrowseButton(step4Group).connect(shell_, setupText_, mainText_, BrowseType.FILE, CanonicalType.EXE, false, null);
		addStep(step4Group);

		Group step5Group = createGroup(shell_, text_.get("dialog.addgamewizard.step5"), new GridLayout());
		Group installedFilesGroup = createGroup(step5Group, new GridData(SWT.FILL, SWT.CENTER, true, false), text_.get("dialog.addgamewizard.installedfiles"), 3);
		installedFilesList_ = createList(installedFilesGroup, SWT.V_SCROLL | SWT.BORDER | SWT.MULTI, 3, 1);
		dstDirectory_ = createLabelAndText(installedFilesGroup, text_.get("dialog.migration.to"), FileLocationService.getInstance().getDosroot().getPath());
		new BrowseButton(installedFilesGroup).connect(shell_, dstDirectory_, null, BrowseType.DIR, CanonicalType.NONE, false, null);
		Group orgImagesGroup = createGroup(step5Group, new GridData(SWT.FILL, SWT.CENTER, true, false), text_.get("dialog.addgamewizard.originalimages"), 2);
		orgImagesList_ = createList(orgImagesGroup, SWT.V_SCROLL | SWT.BORDER | SWT.MULTI, 2, 1);
		moveImages_ = createLabelAndCheckButton(orgImagesGroup, text_.get("dialog.addgamewizard.moveimages"), false);
		imagesDstDirectory_ = createLabelAndText(orgImagesGroup, text_.get("dialog.migration.to"));
		imagesDstDirectory_.setEnabled(moveImages_.getSelection());
		moveImages_.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				imagesDstDirectory_.setEnabled(moveImages_.getSelection());
			}
		});
		addStep(step5Group);

		Group step6Group = createGroup(shell_, text_.get("dialog.addgamewizard.step6"), 3);
		Combo template = createLabelAndCombo(step6Group, text_.get("dialog.profile.template"), templatesList_.stream().map(x -> x.getTitle()).toArray(String[]::new), 10,
			TemplateRepository.indexOfDefault(templatesList_));
		createButton(step6Group, null, text_.get("dialog.profile.reloadsettings"), text_.get("dialog.profile.reloadsettings.tooltip"), new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				if (template.getSelectionIndex() != -1) {
					doReloadTemplate(templatesList_.get(template.getSelectionIndex()));
				}
			}
		});
		machine_ = createLabelAndCombo(step6Group, text_.get("dialog.template.machine"), 2,
			profile_.getDosboxVersion().isUsingNewMachineConfig() ? settings_.getValues("profile", "machine073"): settings_.getValues("profile", "machine"), 20,
			text_.get("dialog.template.machine.tooltip"));
		core_ = createLabelAndCombo(step6Group, text_.get("dialog.template.core"), 2, settings_.getValues("profile", "core"), 20, text_.get("dialog.template.core.tooltip"));
		cycles_ = createLabelAndEditableCombo(step6Group, text_.get("dialog.template.cycles"), 2, settings_.getValues("profile", "cycles"), 15, text_.get("dialog.template.cycles.tooltip"));
		mapper_ = createLabelAndCombo(step6Group, text_.get("dialog.template.mapperfile"), 2,
			new String[] {text_.get("dialog.addgamewizard.mapper.generic"), text_.get("dialog.addgamewizard.mapper.specific")}, 5, text_.get("dialog.template.mapperfile.tooltip"));
		mapper_.select(settings_.getBooleanValue("addgamewizard", "useuniquemapperfile") ? 1: 0);
		mapper_.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				settings_.setBooleanValue("addgamewizard", "useuniquemapperfile", ((Combo)event.widget).getSelectionIndex() == 1);
			}
		});
		addStep(step6Group);

		updateControlsByProfile();
	}

	@Override
	protected void onShellOpened() {
		super.onShellOpened();

		title_.setFocus();
	}

	@Override
	protected int stepSize(int step, boolean forward) {
		if (btnPreinstalledGame_.getSelection()) {
			if ((forward && step == 0) || (!forward && step == 4))
				return 4; // skip installing and patching and maincombo
			if ((forward && step == 4) || (!forward && step == 6))
				return 2; // skip moving game data
		} else {
			if ((forward && step == 3) || (!forward && step == 5))
				return 2; // skip maintext
		}
		return super.stepSize(step, forward);
	}

	@Override
	protected boolean onNext(int step) {
		GeneralPurposeDialogs.initErrorDialog();
		if (step == 0) {
			return titleEntered() && doWebSearch();
		} else if (step == 1) {
			return installExeEntered() && runInstallerAndCheckResults();
		} else if (step == 2) {
			return determineMainAndSetup();
		} else if (step == 3) {
			return mainExeEntered() && setMain();
		} else if (step == 4) {
			return mainExeEntered() && setMain();
		} else if (step == 5) {
			return conditionsOkForStep5();
		} else if (step == 6) {
			return createProfile();
		}
		return false;
	}

	@Override
	protected void onClose() {
		super.onClose();
		try {
			org.apache.commons.io.FileUtils.deleteDirectory(FileLocationService.getInstance().getTmpInstallDir());
		} catch (IOException e) {
			GeneralPurposeDialogs.warningMessage(shell_, e);
		}
	}

	private void updateControlsByProfile() {
		Configuration combinedConf = profile_.getCombinedConfiguration();
		machine_.setText(combinedConf.getValue("dosbox", "machine"));
		core_.setText(combinedConf.getValue("cpu", "core"));
		cycles_.setText(combinedConf.getValue("cpu", "cycles"));
	}

	private void updateProfileByControls() {
		profile_.setValue("dosbox", "machine", machine_.getText());
		profile_.setValue("cpu", "core", core_.getText());
		profile_.setValue("cpu", "cycles", cycles_.getText());
	}

	private void doReloadTemplate(Template template) {
		try {
			StringBuffer warningsLog = new StringBuffer();

			warningsLog.append(template.resetAndLoadConfiguration());
			warningsLog.append(profile_.reloadTemplate(profile_.getDosboxVersion(), template));

			updateControlsByProfile();

			if (StringUtils.isNotEmpty(warningsLog))
				GeneralPurposeDialogs.warningMessage(getParent(), warningsLog.toString());
		} catch (IOException e) {
			GeneralPurposeDialogs.warningMessage(getParent(), e);
		}
	}

	private boolean titleEntered() {
		if (StringUtils.isBlank(title_.getText()))
			GeneralPurposeDialogs.addError(text_.get("dialog.profile.required.title"), title_);
		return !GeneralPurposeDialogs.displayErrorDialog(shell_);
	}

	private boolean doWebSearch() {
		String currTitle = title_.getText();

		if ((Boolean)loadSharedConfButton_.getData("selected")) {
			try {
				Client client = ClientBuilder.newClient();
				GenericType<List<SharedConf>> confType = new GenericType<List<SharedConf>>() {
				};
				List<SharedConf> confs = client.target(settings_.getValue("confsharing", "endpoint")).path("/configurations/bytitle/{i}").resolveTemplate("i", currTitle).request().accept(
					MediaType.APPLICATION_XML).get(confType);
				client.close();

				if (confs.size() == 0) {
					GeneralPurposeDialogs.infoMessage(shell_, text_.get("general.notice.searchenginenoresults", new String[] {Constants.DBCONFWS, currTitle}));
				} else {
					SharedConfLoading result = new LoadSharedConfDialog(shell_, currTitle, confs).open();
					if (result != null) {
						if (result.reloadDosboxDefaults_)
							profile_.getConfiguration().clearSections();
						profile_.loadConfigurationData(text_, result.conf_.getIncrConf(), new File(result.conf_.getGameTitle()));
						updateControlsByProfile();
					}
				}
			} catch (Exception e) {
				GeneralPurposeDialogs.warningMessage(shell_, text_.get("general.error.retrieveinfosearchengine", new String[] {Constants.DBCONFWS, currTitle, StringRelatedUtils.toString(e)}), e);
			}
		}

		if (engineSelector_.isSelected()) {
			WebSearchEngine engine = WebSearchEngine.getBySimpleName(settings_.getValue("gui", "searchengine"));
			try {
				WebProfile thisGame = null;
				List<WebProfile> webGamesList = engine.getEntries(currTitle, settings_.getValues(engine.getSimpleName(), "platform_filter"));
				if (webGamesList.size() >= 1) {
					thisGame = new BrowseSearchEngineDialog(shell_, currTitle, webGamesList, engine).open();
				}
				if (thisGame != null) {
					WebProfile profExt = engine.getEntryDetailedInformation(thisGame);
					if (settings_.getBooleanValue(engine.getSimpleName(), "set_title"))
						title_.setText(profExt.getTitle());
					if (settings_.getBooleanValue(engine.getSimpleName(), "set_developer"))
						profile_.setDeveloper(profExt.getDeveloperName());
					if (settings_.getBooleanValue(engine.getSimpleName(), "set_publisher"))
						profile_.setPublisher(profExt.getPublisherName());
					if (settings_.getBooleanValue(engine.getSimpleName(), "set_year"))
						profile_.setYear(profExt.getYear());
					if (settings_.getBooleanValue(engine.getSimpleName(), "set_genre"))
						profile_.setGenre(profExt.getGenre());
					if (settings_.getBooleanValue(engine.getSimpleName(), "set_link"))
						profile_.getLinks()[0] = new Link(text_.get("dialog.profile.searchengine.link.maininfo", new String[] {engine.getName()}), profExt.getUrl());
					if (settings_.getBooleanValue(engine.getSimpleName(), "set_description"))
						profile_.setNotes(profExt.getNotes());
					if (settings_.getBooleanValue(engine.getSimpleName(), "set_rank"))
						profile_.getCustomInts()[0] = profExt.getRank();
				}
			} catch (Exception e) {
				GeneralPurposeDialogs.warningMessage(shell_, text_.get("general.error.retrieveinfosearchengine", new String[] {engine.getName(), currTitle, StringRelatedUtils.toString(e)}), e);
			}
		}

		if (btnGameNeedsToBeInstalled_.getSelection() && StringUtils.isBlank(installExe_.getText()))
			resetMounts();

		return true;
	}

	private boolean installExeEntered() {
		if (StringUtils.isBlank(installExe_.getText()))
			GeneralPurposeDialogs.addError(text_.get("dialog.addgamewizard.required.installexe"), installExe_);
		return !GeneralPurposeDialogs.displayErrorDialog(shell_);
	}

	private boolean runInstallerAndCheckResults() {
		try {
			FileUtils.deleteDirectory(FileLocationService.getInstance().getTmpInstallDir());
			FilesUtils.createDir(FileLocationService.getInstance().getTmpInstallDir());

			profile_.setAutoexecSettings(installExe_.getText(), installParameters_.getText());

			ExecuteUtils.doRunProfile(ProfileRunMode.INSTALLER, profile_, btnInstallManual_.getSelection(), display_);

			shell_.forceFocus();
			shell_.forceActive();

			orgImages_ = new ArrayList<>();
			File[] firstImageMountPath = profile_.getConfiguration().getAutoexec().findFirstImageMountCanonicalPath();
			for (File file: firstImageMountPath) {
				orgImages_.add(toImageFileLocation(file));
			}
			List<FileLocation> additionalImageFiles = new ArrayList<>();
			for (FileLocation orgImage: orgImages_) {
				File file = orgImage.getCanonicalFile();
				if (file.getName().toLowerCase().endsWith(FilesUtils.CDIMAGES[1])) { // cue sheet
					File binFile = ISO9660FileSystem.parseCueSheet(file);
					if (binFile != null && file.getParentFile().equals(binFile.getParentFile())) {
						additionalImageFiles.add(toImageFileLocation(binFile));
					}
				}
			}
			orgImages_.addAll(additionalImageFiles);

			installedFiles_ = new ArrayList<>();
			File[] files = FileLocationService.getInstance().getTmpInstallDir().listFiles();
			for (File file: files)
				installedFiles_.add(toImageFileLocation(file));
			if (installedFiles_.isEmpty()) {
				GeneralPurposeDialogs.warningMessage(shell_, text_.get("dialog.addgamewizard.error.nofilesinstalled"));
				return false;
			}

			return true;
		} catch (IOException e) {
			GeneralPurposeDialogs.warningMessage(shell_, e);
			return false;
		}
	}

	private static FileLocation toImageFileLocation(File file) {
		return new FileLocation(file.getPath(), FileLocationService.getInstance().dosrootRelative());
	}

	private boolean determineMainAndSetup() {
		if (StringUtils.isNotBlank(patchExe_.getText())) {
			try {
				profile_.setAutoexecSettings(patchExe_.getText(), patchParameters_.getText());

				ExecuteUtils.doRunProfile(ProfileRunMode.INSTALLER, profile_, btnPatchManual_.getSelection(), shell_.getDisplay());

				shell_.forceFocus();
				shell_.forceActive();
			} catch (IOException e) {
				GeneralPurposeDialogs.warningMessage(shell_, e);
				return false;
			}
		}

		orgImagesList_.removeAll();
		if (orgImages_ != null) {
			for (FileLocation orgImage: orgImages_) {
				orgImagesList_.add(orgImage.getFile().getPath());
			}
		}
		orgImagesList_.selectAll();
		orgImagesList_.pack();
		orgImagesList_.getParent().layout();

		installedFilesList_.removeAll();
		File gameDir = null;
		for (FileLocation installedFile: installedFiles_) {
			if (installedFile.getFile().isDirectory()) {
				installedFilesList_.add("[ " + installedFile.getFile().getPath() + " ]");
				if (gameDir == null)
					gameDir = installedFile.getCanonicalFile();
			} else {
				installedFilesList_.add(installedFile.getFile().getPath());
			}
		}
		installedFilesList_.selectAll();
		installedFilesList_.pack();
		installedFilesList_.getParent().layout();

		moveImages_.setEnabled(profile_.getConfiguration().getAutoexec().countImageMounts() == 1);
		String imagesDirString = settings_.getValue("directory", "orgimages");
		File imagesSubDir = gameDir != null ? new File(gameDir.getName(), imagesDirString): new File(imagesDirString);
		imagesDstDirectory_.setText(imagesSubDir.getPath());

		List<File> executables = FilesUtils.listExecutablesInDirRecursive(FileLocationService.getInstance().getTmpInstallDir());

		main_.removeAll();
		setup_.removeAll();
		setup_.add(StringUtils.EMPTY);
		for (File f: executables) {
			String filename = toImageFileLocation(f).getFile().getPath();
			main_.add(filename);
			setup_.add(filename);
		}
		if (executables.isEmpty())
			main_.add(installExe_.getText());
		int mainFileIndex = DosGameUtils.findMostLikelyMainIndex(title_.getText(), executables);
		if (mainFileIndex != -1) {
			main_.select(mainFileIndex);
		} else {
			main_.select(0);
		}
		int setupFileIndex = DosGameUtils.findSetupIndex(executables);
		if (setupFileIndex != -1) {
			setup_.select(setupFileIndex + 1);
		} else {
			setup_.select(0);
		}
		setup_.setEnabled(setup_.getItemCount() > 1);
		return true;
	}

	private boolean mainExeEntered() {
		if (btnPreinstalledGame_.getSelection()) {
			if (StringUtils.isBlank(mainText_.getText()))
				GeneralPurposeDialogs.addError(text_.get("dialog.profile.required.mainexe"), mainText_);
		} else {
			if (StringUtils.isBlank(main_.getText()))
				GeneralPurposeDialogs.addError(text_.get("dialog.profile.required.mainexe"), main_);
		}
		return !GeneralPurposeDialogs.displayErrorDialog(shell_);
	}

	private boolean setMain() {
		if (btnPreinstalledGame_.getSelection()) {
			if (profile_.getRequiredMount(false, mainText_.getText(), false, false) != null) {
				profile_.addRequiredMount(false, mainText_.getText(), false);
			}
			profile_.setAutoexecSettings(mainText_.getText(), StringUtils.EMPTY);
		} else {
			if (profile_.getRequiredMount(false, main_.getText(), false, false) != null) {
				profile_.addRequiredMount(false, main_.getText(), false);
			}
			profile_.setAutoexecSettings(main_.getText(), StringUtils.EMPTY);
		}
		return true;
	}

	private boolean conditionsOkForStep5() {
		if (btnPreinstalledGame_.getSelection())
			return true;

		try {
			if (installedFilesList_.getSelectionCount() > 0) {
				File destDir = new File(dstDirectory_.getText());
				if (!destDir.isDirectory()) {
					if (GeneralPurposeDialogs.confirmMessage(shell_, text_.get("dialog.addgamewizard.confirm.createdestinationdir", new String[] {destDir.toString()}))) {
						destDir.mkdirs();
					}
				}
				if (!destDir.isDirectory()) {
					GeneralPurposeDialogs.addError(text_.get("dialog.addgamewizard.error.destinationdirmissing", new String[] {destDir.toString()}), dstDirectory_);
				} else {
					for (int i = 0; i < installedFiles_.size(); i++) {
						if (installedFilesList_.isSelected(i)) {
							File destFile = new File(destDir, installedFiles_.get(i).getFile().getName());
							if (org.apache.commons.io.FileUtils.directoryContains(destDir, destFile)) {
								GeneralPurposeDialogs.addError(text_.get("dialog.addgamewizard.error.gamedatadirexists", new String[] {destFile.toString()}), dstDirectory_);
							}
						}
					}
				}
			} else {
				GeneralPurposeDialogs.addError(text_.get("dialog.addgamewizard.error.gamedatamustbemoved"), installedFilesList_);
			}

			return !GeneralPurposeDialogs.displayErrorDialog(shell_);
		} catch (IOException e) {
			GeneralPurposeDialogs.warningMessage(shell_, e);
			return false;
		}
	}

	private boolean createProfile() {
		try {

			String setupString = btnPreinstalledGame_.getSelection() ? setupText_.getText(): setup_.getText();

			profile_.setTitle(title_.getText());
			profile_.setSetupFileLocation(setupString);

			if (installedFilesList_.getSelectionCount() > 0) {
				FileLocation destDir = new FileLocation(dstDirectory_.getText(), FileLocationService.getInstance().dosrootRelative());

				profile_.migrate(FileLocationService.getInstance().getTmpInstallLocation(), destDir);
				profile_.removeFloppyMounts();
				profile_.removeUnnecessaryMounts();

				for (int i = 0; i < installedFiles_.size(); i++) {
					File src = installedFiles_.get(i).getCanonicalFile();
					if (installedFilesList_.isSelected(i)) {
						FileUtils.moveToDirectory(src, destDir.getCanonicalFile(), true);
					}
				}

				if (moveImages_.getSelection()) {
					File imgDestDir = new File(destDir.getCanonicalFile(), imagesDstDirectory_.getText());

					for (int i = 0; i < orgImages_.size(); i++) {
						FileLocation src = orgImages_.get(i);
						if (orgImagesList_.isSelected(i)) {
							FileUtils.moveToDirectory(src.getCanonicalFile(), imgDestDir, true);
							FileLocation dst = new FileLocation(FilesUtils.concat(imgDestDir, src.getFile().getName()), destDir.getCanonicalizer());
							profile_.getConfiguration().getAutoexec().migrate(src, dst);
						}
					}
				}
			}

			if (mapper_.getSelectionIndex() == 1)
				profile_.setValue("sdl", "mapperfile", settings_.getValue("profile", "uniquemapperfile"));

			updateProfileByControls();

			result_ = new ProfileRepository().add(profile_);

		} catch (IOException | SQLException e) {
			GeneralPurposeDialogs.warningMessage(shell_, e);
		}

		return true;
	}

	private void resetMounts() {
		profile_.getConfiguration().getAutoexec().getMountingpoints().clear();
		profile_.unmountDosboxMounts();
		profile_.getConfiguration().getAutoexec().addMount("mount C \"" + FileLocationService.getInstance().getTmpInstallDir() + "\"");
		mountingpoints_.setItems(profile_.getMountStringsForUI());
	}
}
