/*
 *  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.io.IOException;
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.lang3.StringUtils;
import org.dbgl.constants.Constants;
import org.dbgl.gui.GeneralPurposeDialogs;
import org.dbgl.gui.abstractdialog.EditProfileDialog;
import org.dbgl.gui.dialog.LoadSharedConfDialog.SharedConfLoading;
import org.dbgl.model.FileLocation;
import org.dbgl.model.SearchEngineImageInformation.SearchEngineImageType;
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.entity.SharedConf;
import org.dbgl.model.entity.TemplateProfileBase;
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.FilesUtils;
import org.dbgl.util.StringRelatedUtils;
import org.dbgl.util.searchengine.WebSearchEngine;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.ScrolledComposite;
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.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;


public class EditSingleProfileDialog extends EditProfileDialog<Profile> {

	private final static boolean multiEdit = false;

	private Profile profile_;
	private final String sendTo_;
	private final boolean editing_;
	private final boolean focusOnTitle_;

	public EditSingleProfileDialog(Shell parent, Profile prof, String sendTo, boolean focusOnTitle) {
		super(parent);
		profile_ = prof;
		sendTo_ = sendTo;
		focusOnTitle_ = focusOnTitle;

		editing_ = profile_ != null;
	}

	@Override
	protected String getDialogTitle() {
		if (editing_)
			return text_.get("dialog.profile.title.edit", new Object[] {profile_.getTitle(), profile_.getId()});
		else if (sendTo_ != null)
			return text_.get("dialog.profile.title.send", new Object[] {sendTo_});
		else
			return text_.get("dialog.profile.title.add");
	}

	@Override
	protected boolean prepare() {
		if (!super.prepare())
			return false;

		try {
			StringBuffer warningsLog = new StringBuffer();

			if (editing_) {
				dbversionIndex_ = DosboxVersionRepository.indexOf(dbversionsList_, profile_.getDosboxVersion());
			} else {
				Template template = TemplateRepository.findDefault(templatesList_);

				if (template != null)
					warningsLog.append(template.resetAndLoadConfiguration());

				profile_ = ProfileFactory.create(DosboxVersionRepository.findDefault(dbversionsList_), template);

				if (sendTo_ != null) {
					if (FilesUtils.isConfFile(sendTo_)) {
						profile_.setConfigurationFileLocation(sendTo_);
					} else if (FilesUtils.isExecutable(sendTo_)) {
						profile_.getConfiguration().getAutoexec().setGameMain(new FileLocation(sendTo_, FileLocationService.getInstance().dosrootRelative()).getFile().getPath());
					} else if (FilesUtils.isBooterImage(sendTo_)) {
						profile_.getConfiguration().getAutoexec().setImg1(new FileLocation(sendTo_, FileLocationService.getInstance().dosrootRelative()).getFile().getPath());
					}
				}
			}

			warningsLog.append(profile_.resetAndLoadConfiguration());

			if (StringUtils.isNotBlank(warningsLog))
				GeneralPurposeDialogs.warningMessage(getParent(), warningsLog.toString());
			return true;
		} catch (Exception e) {
			GeneralPurposeDialogs.warningMessage(getParent(), e);
			return false;
		}
	}

	private void updateControlsByProfile() {
		metaControls_.forEach(x -> x.setControlByProfile(profile_, multiEdit));

		updateControlsByConfigurable(profile_, multiEdit);
	}

	@Override
	protected void updateControlsByConfigurable(TemplateProfileBase configurable, boolean multiEdit) {
		super.updateControlsByConfigurable(configurable, multiEdit);

		loadfixValue_.setEnabled(loadfix_.getSelection());
	}

	protected void updateProfileByControls() {
		metaControls_.forEach(x -> x.updateProfileByControl(profile_));

		super.updateConfigurableByControls(profile_);
	}

	protected void doPerformDosboxConfAction(DosboxConfAction action, DosboxVersion newDosboxVersion) {
		try {
			StringBuffer warningsLog = new StringBuffer();

			updateProfileByControls();

			warningsLog.append(newDosboxVersion.resetAndLoadConfiguration());

			if (action == DosboxConfAction.SET) {
				warningsLog.append(profile_.setToDosboxVersion(newDosboxVersion));
			} else if (action == DosboxConfAction.SWITCH) {
				warningsLog.append(profile_.switchToDosboxVersion(newDosboxVersion));
			} else if (action == DosboxConfAction.RELOAD) {
				warningsLog.append(profile_.reloadDosboxVersion(newDosboxVersion));
			} else if (action == DosboxConfAction.RELOAD_TEMPLATE) {
				Template templ = templatesList_.get(templateCombo_.getSelectionIndex());
				warningsLog.append(templ.resetAndLoadConfiguration());
				warningsLog.append(profile_.reloadTemplate(newDosboxVersion, templ));
			}

			updateControlsByConfigurable(profile_, multiEdit);

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

	@Override
	protected void onShellCreated() {
		createInfoTab();
		createGeneralTab(editing_ ? profile_.getCanonicalCaptures().getPath(): text_.get("dialog.profile.automatic"), editing_ ? profile_.getConfigurationCanonicalFile().getPath()
				: SettingsDialog.confLocations[settings_.getIntValue("profiledefaults", "confpath")] + ", " + SettingsDialog.confFilenames[settings_.getIntValue("profiledefaults", "conffile")]);
		createDisplayTab();
		createMachineTab();
		createAudioTab();
		createIOTab();
		createCustomCommandsTab(profile_, multiEdit);
		createMountingTab(profile_, multiEdit);
		createOkCancelButtons();

		updateControlsByProfile();

		if (!editing_ || focusOnTitle_) {
			title_.selectAll();
			title_.setFocus();
		}

		final VerifyListener addMountListener = new VerifyListener() {
			public void verifyText(VerifyEvent event) {
				if (event.text.length() > 1) {
					if (mountingpointsList_.getItemCount() == 0) {
						boolean booter = event.widget == img1_ || event.widget == img2_ || event.widget == img3_;
						profile_.addRequiredMount(booter, event.text, false);
						mountingpointsList_.setItems(profile_.getMountStringsForUI());
					}
				}
			}
		};

		main_.addVerifyListener(addMountListener);
		setup_.addVerifyListener(addMountListener);
		img1_.addVerifyListener(addMountListener);
		img2_.addVerifyListener(addMountListener);
		img3_.addVerifyListener(addMountListener);
	}

	@Override
	protected ToolBar createInfoTab() {
		ToolBar toolBar = super.createInfoTab();

		ToolItem engineToolItem = engineSelector_.getToolItem();
		engineToolItem.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				if (event.detail != SWT.ARROW) {

					final int WEB_IMAGE_WIDTH = settings_.getIntValue("mobygames", "image_width");
					final int WEB_IMAGE_HEIGHT = settings_.getIntValue("mobygames", "image_height");
					final int WEB_IMAGE_COLUMNS = settings_.getIntValue("mobygames", "image_columns");
					final int DIALOG_RESIZE_WIDTH = ((WEB_IMAGE_WIDTH + 10) * WEB_IMAGE_COLUMNS) + (3 * (WEB_IMAGE_COLUMNS - 1)) + 19;

					WebSearchEngine engine = WebSearchEngine.getBySimpleName(settings_.getValue("gui", "searchengine"));

					WebProfile orgProf = (WebProfile)engineToolItem.getData("profile");
					if (orgProf == null) {
						String currTitle = title_.getText();
						if (currTitle.length() >= 1) {
							try {
								WebProfile thisGame = null;
								List<WebProfile> webGamesList = engine.getEntries(currTitle, settings_.getValues(engine.getSimpleName(), "platform_filter"));
								if (webGamesList.size() == 0) {
									GeneralPurposeDialogs.infoMessage(shell_, text_.get("general.notice.searchenginenoresults", new String[] {engine.getName(), currTitle}));
								} else if (webGamesList.size() == 1) {
									thisGame = webGamesList.get(0);
								} else {
									thisGame = new BrowseSearchEngineDialog(shell_, currTitle, webGamesList, engine).open();
								}
								if (thisGame != null) {
									WebProfile profExt = engine.getEntryDetailedInformation(thisGame);

									WebProfile currentProf = new WebProfile();
									currentProf.setTitle(title_.getText());
									currentProf.setDeveloperName(developer_.getText());
									currentProf.setPublisherName(publisher_.getText());
									currentProf.setYear(year_.getText());
									currentProf.setGenre(genre_.getText());
									currentProf.setUrl(link_[0].getText());
									currentProf.setPlatform(linkTitle_[0].getText());
									currentProf.setNotes(notes_.getText());
									currentProf.setRank(custom9_.getSelection());
									engineToolItem.setData("profile", currentProf);
									engineToolItem.setImage(ImageService.getResourceImage(display_, ImageService.IMG_UNDO));
									engineToolItem.setToolTipText(text_.get("dialog.profile.undosearchengine"));

									if (settings_.getBooleanValue(engine.getSimpleName(), "set_title"))
										title_.setText(profExt.getTitle());
									if (settings_.getBooleanValue(engine.getSimpleName(), "set_developer"))
										developer_.setText(profExt.getDeveloperName());
									if (settings_.getBooleanValue(engine.getSimpleName(), "set_publisher"))
										publisher_.setText(profExt.getPublisherName());
									if (settings_.getBooleanValue(engine.getSimpleName(), "set_year"))
										year_.setText(profExt.getYear());
									if (settings_.getBooleanValue(engine.getSimpleName(), "set_genre"))
										genre_.setText(profExt.getGenre());
									if (settings_.getBooleanValue(engine.getSimpleName(), "set_link")) {
										link_[0].setText(profExt.getUrl());
										linkTitle_[0].setText(text_.get("dialog.profile.searchengine.link.maininfo", new String[] {engine.getName()}));
									}
									if (settings_.getBooleanValue(engine.getSimpleName(), "set_description")) {
										String n = notes_.getText();
										String p = profExt.getNotes().replaceAll("\n", notes_.getLineDelimiter());
										if (!n.endsWith(p)) {
											if (n.length() > 0) {
												notes_.append(notes_.getLineDelimiter() + notes_.getLineDelimiter());
											}
											notes_.append(p);
										}
									}
									if (settings_.getBooleanValue(engine.getSimpleName(), "set_rank"))
										custom9_.setSelection(profExt.getRank());

									int ca = settings_.getBooleanValue(engine.getSimpleName(), "choose_coverart") ? Integer.MAX_VALUE: 0;
									int ss = settings_.getBooleanValue(engine.getSimpleName(), "choose_screenshot") ? Integer.MAX_VALUE: 0;
									if ((ca > 0) || (ss > 0)) {
										boolean forceAllRegionsCoverArt = settings_.getBooleanValue(engine.getSimpleName(), "force_all_regions_coverart");
										imageInformation_ = engine.getEntryImages(profExt, ca, ss, forceAllRegionsCoverArt);

										webImagesSpaceHolder_ = createInnerComposite(contents_, new GridData(SWT.FILL, SWT.FILL, false, true), 2);

										if (imageInformation_.length > 0) {
											createButton(webImagesSpaceHolder_, new GridData((WEB_IMAGE_WIDTH + 10), SWT.DEFAULT), text_.get("button.all"), null, new SelectionAdapter() {
												public void widgetSelected(SelectionEvent e) {
													for (Button but: imgButtons_)
														but.setSelection(true);
												}
											});
											createButton(webImagesSpaceHolder_, new GridData((WEB_IMAGE_WIDTH + 10), SWT.DEFAULT), text_.get("button.none"), null, new SelectionAdapter() {
												public void widgetSelected(SelectionEvent e) {
													for (Button but: imgButtons_)
														but.setSelection(false);
												}
											});
										}

										ScrolledComposite webImagesSpace = new ScrolledComposite(webImagesSpaceHolder_, SWT.V_SCROLL);
										webImagesSpace.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
										webImagesSpace.setLayout(new GridLayout());
										webImagesSpace.getVerticalBar().setIncrement(WEB_IMAGE_HEIGHT / WEB_IMAGE_COLUMNS);
										webImagesSpace.getVerticalBar().setPageIncrement((WEB_IMAGE_HEIGHT / WEB_IMAGE_COLUMNS) * 8);

										GridLayout gridLayoutImagesGroup = new GridLayout(WEB_IMAGE_COLUMNS, true);
										gridLayoutImagesGroup.marginHeight = 0;
										gridLayoutImagesGroup.marginWidth = 0;
										gridLayoutImagesGroup.horizontalSpacing = 1;
										gridLayoutImagesGroup.verticalSpacing = 1;
										Composite webImagesComposite = createComposite(webImagesSpace, null, gridLayoutImagesGroup);

										webImagesSpace.setContent(webImagesComposite);

										if (imageInformation_.length > 0) {
											imgButtons_ = new Button[imageInformation_.length];

											for (int i = 0; i < imageInformation_.length; i++) {
												imgButtons_[i] = createImageButton(webImagesComposite, SWT.TOGGLE | SWT.FLAT, new GridData(SWT.LEFT, SWT.BOTTOM, true, true),
													ImageService.getEmptyImage(display_, WEB_IMAGE_WIDTH, WEB_IMAGE_HEIGHT), imageInformation_[i].getDescription());

												final int j = i;
												Thread thread = new Thread() {
													public void run() {
														try {
															ImageData imgData = profExt.getWebImage(j);
															if (!shell_.isDisposed() && !imgButtons_[j].isDisposed()) {
																Image img = ImageService.getWidthLimitedImage(display_, WEB_IMAGE_WIDTH, imgData);
																if (!shell_.isDisposed() && !imgButtons_[j].isDisposed()) {
																	shell_.getDisplay().syncExec(new Runnable() {
																		public void run() {
																			imgButtons_[j].getImage().dispose();
																			imgButtons_[j].setImage(img);
																			webImagesComposite.setSize(webImagesComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
																			webImagesComposite.layout();
																		}
																	});
																}
															}
														} catch (IOException e) {
														}
													}
												};
												thread.start();
											}
										} else {
											GridData gd = new GridData(SWT.CENTER, SWT.FILL, true, true, WEB_IMAGE_COLUMNS, 1);
											gd.widthHint = (WEB_IMAGE_WIDTH + 10) * WEB_IMAGE_COLUMNS + (3 * (WEB_IMAGE_COLUMNS - 1)) + 2;
											gd.verticalIndent = WEB_IMAGE_HEIGHT / 2;
											createLabel(webImagesComposite, SWT.WRAP | SWT.CENTER, gd, text_.get("dialog.profile.notice.noimagesfound", new String[] {engine.getName()}));
										}

										setListenerEnabled(false);
										webImagesComposite.pack();
										shell_.setSize(shell_.getSize().x + DIALOG_RESIZE_WIDTH, shell_.getSize().y);
										shell_.layout();
									}
								}
							} catch (Exception e) {
								GeneralPurposeDialogs.warningMessage(shell_,
									text_.get("general.error.retrieveinfosearchengine", new String[] {engine.getName(), currTitle, StringRelatedUtils.toString(e)}), e);
							}
						}
					} else {
						title_.setText(orgProf.getTitle());
						developer_.setText(orgProf.getDeveloperName());
						publisher_.setText(orgProf.getPublisherName());
						year_.setText(orgProf.getYear());
						genre_.setText(orgProf.getGenre());
						link_[0].setText(orgProf.getUrl());
						linkTitle_[0].setText(orgProf.getPlatform());
						notes_.setText(orgProf.getNotes());
						custom9_.setSelection(orgProf.getRank());

						engineToolItem.setData("profile", null);
						engineToolItem.setImage(ImageService.getResourceImage(display_, engine.getIcon()));
						engineToolItem.setToolTipText(text_.get("dialog.profile.consultsearchengine", new String[] {engine.getName()}));

						if (webImagesSpaceHolder_ != null) {
							webImagesSpaceHolder_.dispose();
							webImagesSpaceHolder_ = null;
							shell_.setSize(shell_.getSize().x - DIALOG_RESIZE_WIDTH, shell_.getSize().y);
							shell_.layout();
							setListenerEnabled(true);
							imageInformation_ = null;
						}
					}
				}
			}
		});

		createImageToolItem(toolBar, SWT.PUSH, ImageService.getResourceImage(display_, ImageService.IMG_SHARE), text_.get("button.consultconfsearchengine", new String[] {Constants.DBCONFWS}),
			new SelectionAdapter() {
				public void widgetSelected(SelectionEvent event) {
					String currTitle = title_.getText();
					if (currTitle.length() >= 1) {
						try {
							Client client = ClientBuilder.newClient();
							List<SharedConf> confs = client.target(settings_.getValue("confsharing", "endpoint")).path("/configurations/bytitle/{i}").resolveTemplate("i", currTitle).request().accept(
								MediaType.APPLICATION_XML).get(new GenericType<List<SharedConf>>() {
								});
							client.close();

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

		return toolBar;
	}

	protected void createOkCancelButtons() {
		createOkCancelButtons(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				if (!isValid()) {
					return;
				}
				try {
					updateProfileByControls();

					if (editing_) {
						new ProfileRepository().update(profile_);
						result_ = profile_;
					} else {
						result_ = new ProfileRepository().add(profile_);
					}

					if (imageInformation_ != null) {
						File canonicalCapturesDir = profile_.getCanonicalCaptures();
						for (int i = 0; i < imageInformation_.length; i++) {
							if (imgButtons_[i].getSelection()) {
								String description = FilesUtils.toSafeFilenameForWebImages(imageInformation_[i].getDescription());
								String filename = (imageInformation_[i].getType() == SearchEngineImageType.CoverArt)
										? text_.get("dialog.profile.mobygames.coverartfilename", new Object[] {i, description})
										: text_.get("dialog.profile.mobygames.screenshotfilename", new Object[] {i, description});
								File file = new File(canonicalCapturesDir, filename + ".png");
								if (!FilesUtils.isExistingFile(file)) {
									try {
										ImageService.save(imageInformation_[i].getData(), file.getPath());
									} catch (SWTException e) {
										GeneralPurposeDialogs.warningMessage(shell_, text_.get("general.error.savefile", new Object[] {file.getPath()}), e);
									}
								} else {
									GeneralPurposeDialogs.warningMessage(shell_, text_.get("dialog.profile.error.imagealreadyexists",
										new Object[] {file.getPath(), WebSearchEngine.getBySimpleName(settings_.getValue("gui", "searchengine")).getName()}));
								}
							}
						}
					}
				} catch (Exception e) {
					GeneralPurposeDialogs.warningMessage(shell_, e);
				}
				shell_.close();
			}
		});

		createImageButton(otherButtons_, ImageService.getResourceImage(display_, ImageService.IMG_SHARE), text_.get("button.shareconf"), new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				updateProfileByControls();
				new ShareConfDialog(shell_, title_.getText(), year_.getText(), profile_).open();
			}
		});
	}

	protected boolean isValid() {
		GeneralPurposeDialogs.initErrorDialog();
		String requiredMount = null;
		if (title_.getText().length() == 0) {
			GeneralPurposeDialogs.addError(text_.get("dialog.profile.required.title"), title_, getTabItemByControl(title_));
		}
		if (dosExpandItem_.getExpanded()) {
			if (FilesUtils.isExecutable(main_.getText())) {
				requiredMount = dealWithField(false, main_.getText());
			} else {
				GeneralPurposeDialogs.addError(text_.get("dialog.profile.required.mainexe"), main_, getTabItemByControl(main_));
			}
			if (FilesUtils.isExecutable(setup_.getText())) {
				requiredMount = dealWithField(false, setup_.getText());
			}
		} else {
			if (img1_.getText().length() == 0) {
				GeneralPurposeDialogs.addError(text_.get("dialog.profile.required.booterimage"), img1_, getTabItemByControl(img1_));
			} else {
				requiredMount = dealWithField(true, img1_.getText());
			}
			if (img2_.getText().length() > 0) {
				requiredMount = dealWithField(true, img2_.getText());
			}
			if (img3_.getText().length() > 0) {
				requiredMount = dealWithField(true, img3_.getText());
			}
		}
		if (requiredMount != null) {
			GeneralPurposeDialogs.addError(text_.get("dialog.profile.required.mountlocation"), mountingpointsList_, getTabItemByControl(mountingpointsList_));
		}

		if (setButton_.isEnabled()) {
			GeneralPurposeDialogs.addError(text_.get("dialog.template.required.dosboxassociation"), setButton_, getTabItemByControl(setButton_));
		}
		return !GeneralPurposeDialogs.displayErrorDialog(shell_);
	}

	private String dealWithField(boolean booter, String target) {
		String requiredMount = profile_.getRequiredMount(booter, target, true, false);
		if (requiredMount != null && GeneralPurposeDialogs.confirmMessage(shell_, text_.get("dialog.profile.confirm.addmountlocation", new Object[] {requiredMount}))) {
			profile_.addRequiredMount(booter, target, false);
			mountingpointsList_.setItems(profile_.getMountStringsForUI());
		}
		return profile_.getRequiredMount(booter, target, true, false);
	}
}
