/*
 *  Copyright (C) 2006-2020  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.abstractdialog;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

import org.dbgl.gui.controls.Button_;
import org.dbgl.gui.controls.Chain;
import org.dbgl.gui.controls.Mess_;
import org.dbgl.gui.controls.SearchEngineSelector;
import org.dbgl.gui.controls.TextControl_;
import org.dbgl.model.SearchEngineImageInformation;
import org.dbgl.model.aggregate.Profile;
import org.dbgl.model.aggregate.Template;
import org.dbgl.model.conf.Autoexec;
import org.dbgl.model.entity.ITitledEntity;
import org.dbgl.model.entity.TemplateProfileBase;
import org.dbgl.model.repository.TemplateRepository;
import org.dbgl.model.repository.TitledEntityRepository;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Group;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;


public abstract class EditProfileDialog<T> extends EditConfigurableDialog<T> {

	protected List<ITitledEntity> developersList_, publishersList_, genresList_, yearsList_, statusList_;
	protected List<List<ITitledEntity>> customList_;
	protected List<Template> templatesList_;

	protected Text title_, notes_;
	protected SearchEngineSelector engineSelector_;
	protected Text[] link_, linkTitle_;
	protected Button[] linkBrowseButton_;
	protected Combo developer_, publisher_, genre_, year_;
	protected Scale custom9_;
	protected Combo templateCombo_;
	protected Button loadfix_;
	protected Combo loadfixValue_;
	protected Text img1_, img2_, img3_, main_, setup_;
	protected Composite webImagesSpaceHolder_;
	protected SearchEngineImageInformation[] imageInformation_;
	protected Button[] imgButtons_;

	protected int templateIndex_;

	public EditProfileDialog(Shell parent) {
		super(parent, "profiledialog");
	}

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

		try {
			TemplateRepository templRepo = new TemplateRepository();
			TitledEntityRepository titledRepo = new TitledEntityRepository();

			templatesList_ = templRepo.listAll(dbversionsList_);
			developersList_ = titledRepo.listDevelopers(null);
			publishersList_ = titledRepo.listPublishers(null);
			genresList_ = titledRepo.listGenres(null);
			yearsList_ = titledRepo.listYears(null);
			statusList_ = titledRepo.listStatus(null);

			customList_ = new ArrayList<>();
			for (int i = 0; i < Profile.NR_OF_CUSTOM_STRING_DROPDOWNS; i++) {
				customList_.add(titledRepo.listCustomValues(i, null));
			}

			templateIndex_ = TemplateRepository.indexOfDefault(templatesList_);

			return true;
		} catch (Exception e) {
			Mess_.on(getParent()).exception(e).warning();
			return false;
		}
	}

	protected ToolBar createInfoTab() {
		Composite composite = createTabWithComposite("dialog.profile.tab.info", 6);

		title_ = Chain.on(composite).lbl(l -> l.key("dialog.profile.title")).txt(t -> t.horSpan(4)).meta(metaControls_).profile(Profile::getTitle, Profile::setTitle).text();

		ToolBar toolBar = new ToolBar(composite, SWT.FLAT);

		engineSelector_ = new SearchEngineSelector(toolBar, false);

		developer_ = Chain.on(composite).lbl(l -> l.key("dialog.profile.developer")).cmb(c -> c.horSpan(2).autoSelect(developersList_)).meta(metaControls_).profile(Profile::getDeveloper,
			Profile::setDeveloper).combo();
		publisher_ = Chain.on(composite).lbl(l -> l.key("dialog.profile.publisher")).cmb(c -> c.horSpan(2).autoSelect(publishersList_)).meta(metaControls_).profile(Profile::getPublisher,
			Profile::setPublisher).combo();
		genre_ = Chain.on(composite).lbl(l -> l.key("dialog.profile.genre")).cmb(c -> c.horSpan(2).autoSelect(genresList_)).meta(metaControls_).profile(Profile::getGenre, Profile::setGenre).combo();
		year_ = Chain.on(composite).lbl(l -> l.key("dialog.profile.year")).cmb(c -> c.horSpan(2).autoSelect(yearsList_)).meta(metaControls_).profile(Profile::getYear, Profile::setYear).combo();

		link_ = new Text[Profile.NR_OF_LINK_DESTINATIONS];
		linkBrowseButton_ = new Button[Profile.NR_OF_LINK_TITLES];
		linkTitle_ = new Text[Profile.NR_OF_LINK_TITLES];

		for (int i = 0; i < Profile.NR_OF_LINK_TITLES / 2; i++) {
			int j = i + 1;
			Chain chnLink = Chain.on(composite).lbl(l -> l.key("dialog.profile.link", new Object[] {j})).txt(t -> t).meta(metaControls_).profile(i, Profile::getLinkDestination,
				Profile::setLinkDestination).but(b -> b.browse(false, Button_.BrowseType.FILE, Button_.CanonicalType.DOC, false)).build();
			link_[i] = chnLink.getText();
			linkBrowseButton_[i] = chnLink.getButton();
			linkTitle_[i] = Chain.on(composite).lbl(l -> l.key("dialog.profile.linktitle")).txt(t -> t.horSpan(2)).meta(metaControls_).profile(i, Profile::getLinkTitle, Profile::setLinkTitle).text();
		}

		Chain.on(composite).lbl(l -> l.key("dialog.profile.status")).cmb(c -> c.horSpan(2).autoSelect(statusList_)).meta(metaControls_).profile(Profile::getStatus, Profile::setStatus).build();
		Chain.on(composite).lbl(l -> l.key("dialog.profile.favorite")).but(b -> b.layoutData(new GridData(SWT.FILL, SWT.CENTER, true, false))).lbl(l -> l).meta(metaControls_).profile(
			Profile::getFavorite, Profile::setFavorite).build();

		notes_ = Chain.on(composite).lbl(l -> l.key("dialog.profile.notes")).txt(t -> t.horSpan(5).multi().wrap()).meta(metaControls_).profile(Profile::getNotes, Profile::setNotes).text();
		notes_.setFont(stringToFont(display_, settings_.getValues("gui", "notesfont"), notes_.getFont()));
		notes_.addDisposeListener(new DisposeListener() {
			@Override
			public void widgetDisposed(DisposeEvent arg0) {
				notes_.getFont().dispose();
			}
		});

		Composite customComposite = createTabWithComposite("dialog.profile.tab.custominfo", 5);

		for (int i = 0; i < Profile.NR_OF_CUSTOM_STRING_DROPDOWNS; i++) {
			int j = i + 1;
			int k = i;
			Chain.on(customComposite).lbl(l -> l.txt(settings_.getValue("gui", "custom" + j))).cmb(c -> c.horSpan(4).autoSelect(customList_.get(k))).meta(metaControls_).profile(i,
				Profile::getCustomString, Profile::setCustomString).build();
		}
		for (int i = 0; i < Profile.NR_OF_CUSTOM_STRING_FIELDS_1; i++) {
			int j = i + 1;
			Chain.on(customComposite).lbl(l -> l.txt(settings_.getValue("gui", "custom" + (j + Profile.NR_OF_CUSTOM_STRING_DROPDOWNS)))).txt(t -> t.horSpan(4)).meta(metaControls_).profile(
				i + Profile.NR_OF_CUSTOM_STRING_DROPDOWNS, Profile::getCustomString, Profile::setCustomString).build();
		}

		custom9_ = Chain.on(customComposite).lbl(l -> l.txt(settings_.getValue("gui", "custom9"))).scl(s -> s.horSpan(2)).meta(metaControls_).profile(0, Profile::getCustomInt,
			Profile::setCustomInt).scale();
		Chain.on(customComposite).lbl(l -> l.txt(settings_.getValue("gui", "custom10"))).spn(s -> s.min(Integer.MIN_VALUE).max(Integer.MAX_VALUE)).meta(metaControls_).profile(1, Profile::getCustomInt,
			Profile::setCustomInt).build();
		for (int i = Profile.NR_OF_LINK_TITLES / 2; i < Profile.NR_OF_LINK_TITLES; i++) {
			int j = i + 1;
			Chain chnLink = Chain.on(customComposite).lbl(l -> l.key("dialog.profile.link", new Object[] {j})).txt(t -> t).meta(metaControls_).profile(i, Profile::getLinkDestination,
				Profile::setLinkDestination).but(b -> b.browse(false, Button_.BrowseType.FILE, Button_.CanonicalType.DOC, false)).build();
			link_[i] = chnLink.getText();
			linkBrowseButton_[i] = chnLink.getButton();
			linkTitle_[i] = Chain.on(customComposite).lbl(l -> l.key("dialog.profile.linktitle")).txt(t -> t).meta(metaControls_).profile(i, Profile::getLinkTitle, Profile::setLinkTitle).text();
		}
		for (int i = 0; i < Profile.NR_OF_CUSTOM_STRING_FIELDS_2; i++) {
			int columns = i % 2 == 0 ? 2: 1;
			int j = i + 1;
			Chain.on(customComposite).lbl(
				l -> l.txt(settings_.getValue("gui", "custom" + (j + Profile.NR_OF_CUSTOM_STRING_DROPDOWNS + Profile.NR_OF_CUSTOM_INTS + Profile.NR_OF_CUSTOM_STRING_FIELDS_1)))).txt(
					t -> t.horSpan(columns)).meta(metaControls_).profile(i + Profile.NR_OF_CUSTOM_STRING_DROPDOWNS + Profile.NR_OF_CUSTOM_STRING_FIELDS_1, Profile::getCustomString,
						Profile::setCustomString).build();
		}

		return toolBar;
	}

	@Override
	protected Group createGeneralTab(String capturesText, String configFileText) {
		Group associationGroup = super.createGeneralTab(capturesText, configFileText);

		templateCombo_ = Chain.on(associationGroup).lbl(l -> l.key("dialog.profile.template")).cmb(
			c -> c.horSpan(3).wide().items(templatesList_.stream().map(z -> z.getTitle()).toArray(String[]::new)).select(templateIndex_).visibleItemCount(20)).combo();

		Button_.on(associationGroup).text().key("dialog.profile.reloadsettings").tooltip("dialog.profile.reloadsettings.tooltip").listen(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				if (templateCombo_.getSelectionIndex() != -1) {
					if (setButton_.isEnabled()) {
						Mess_.on(shell_).key("dialog.template.required.dosboxassociation").bind(setButton_, getTabItemByControl(setButton_)).valid();
						return;
					}
					doPerformDosboxConfAction(DosboxConfAction.RELOAD_TEMPLATE, dbversionsList_.get(dbversionCombo_.getSelectionIndex()));
				}
			}
		}).ctrl().setEnabled(dbversionIndex_ != -1);

		return associationGroup;
	}

	@Override
	protected Group createMachineTab() {
		Group memoryGroup = super.createMachineTab();

		loadfix_ = Chain.on(memoryGroup).lbl(l -> l.key("dialog.profile.loadfix")).but(b -> b.listen(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				loadfixValue_.setEnabled(loadfix_.getSelection());
			}
		})).meta(autoexecControls_).autoexec(Autoexec::getLoadfix, Autoexec::setLoadfix).button();

		loadfixValue_ = Chain.on(memoryGroup).cmb(c -> c.editable().items(settings_.getValues("profile", "loadfix_value"))).lbl(l -> l.key("dialog.profile.kb")).meta(autoexecControls_).autoexec(
			Autoexec::getLoadfixValueAsString, Autoexec::setLoadfixValue).combo();

		Chain.on(memoryGroup).lbl(l -> l.key("dialog.profile.loadhigh")).but(b -> b.horSpan(3)).meta(autoexecControls_).autoexec(Autoexec::getLoadhigh, Autoexec::setLoadhigh).build();

		return memoryGroup;
	}

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

		Composite booterComposite = (Composite)booterExpandItem_.getControl();
		booterComposite.setLayout(new GridLayout(4, false));

		Chain img1Chain = Chain.on(booterComposite).lbl(l -> l.key("dialog.profile.booterimage1")).txt(t -> t).meta(autoexecControls_).autoexec(Autoexec::getImg1, Autoexec::setImg1).but(
			b -> b.browse(false, Button_.BrowseType.FILE, Button_.CanonicalType.BOOTER, false)).but(b -> b.grab(mountingpointsList_, true)).build();
		img1_ = img1Chain.getText();

		Chain img2Chain = Chain.on(booterComposite).lbl(l -> l.key("dialog.profile.booterimage2")).txt(t -> t).meta(autoexecControls_).autoexec(Autoexec::getImg2, Autoexec::setImg2).but(
			b -> b.browse(false, Button_.BrowseType.FILE, Button_.CanonicalType.BOOTER, false)).but(b -> b.grab(mountingpointsList_, true)).build();
		img2_ = img2Chain.getText();

		Chain img3Chain = Chain.on(booterComposite).lbl(l -> l.key("dialog.profile.booterimage3")).txt(t -> t).meta(autoexecControls_).autoexec(Autoexec::getImg3, Autoexec::setImg3).but(
			b -> b.browse(false, Button_.BrowseType.FILE, Button_.CanonicalType.BOOTER, false)).but(b -> b.grab(mountingpointsList_, true)).build();
		img3_ = img3Chain.getText();

		Chain.on(booterComposite).lbl(l -> l.key("dialog.profile.booterdriveletter")).cmb(c -> c.horSpan(3).items(new String[] {"", "A", "C", "D"}).visibleItemCount(4)).meta(
			autoexecControls_).autoexec(Autoexec::getImgDriveletter, Autoexec::setImgDriveletter).build();

		booterExpandItem_.setHeight(booterComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);

		Composite dosComposite = (Composite)dosExpandItem_.getControl();
		dosComposite.setLayout(new GridLayout(7, false));

		main_ = Chain.on(dosComposite).lbl(l -> l.key("dialog.profile.mainexe")).txt(t -> t.horSpan(4)).meta(autoexecControls_).autoexec(Autoexec::getMain, Autoexec::setMain).but(
			b -> b.browse(false, Button_.BrowseType.FILE, Button_.CanonicalType.EXE, false)).but(b -> b.grab(mountingpointsList_, false)).text();

		Chain.on(dosComposite).lbl(l -> l).lbl(l -> l.key("dialog.profile.mainparameters")).txt(t -> t.horSpan(3)).lbl(l -> l.horSpan(2)).meta(autoexecControls_).autoexec(Autoexec::getParameters,
			Autoexec::setParameters).build();

		Chain setupChain = Chain.on(dosComposite).lbl(l -> l.key("dialog.profile.setupexe")).txt(t -> t.horSpan(4)).but(
			b -> b.browse(false, Button_.BrowseType.FILE, Button_.CanonicalType.EXE, false)).meta(metaControls_).profile(Profile::getSetupString, Profile::setSetupFileLocation).but(
				b -> b.grab(mountingpointsList_, false)).build();
		setup_ = setupChain.getText();

		Chain.on(dosComposite).lbl(l -> l).lbl(l -> l.key("dialog.profile.setupparameters")).txt(t -> t.horSpan(3)).lbl(l -> l.horSpan(2)).meta(metaControls_).profile(Profile::getSetupParams,
			Profile::setSetupParams).build();

		Text alt1 = Chain.on(dosComposite).lbl(l -> l.key("dialog.profile.altexe", new Object[] {1})).txt(t -> t.horSpan(2)).meta(metaControls_).profile(0, Profile::getAltExeString,
			Profile::setAltExeFileLocation).text();
		Chain alt1Chain = Chain.on(dosComposite).lbl(l -> l).txt(t -> t).but(b -> b.browse(false, Button_.BrowseType.FILE, Button_.CanonicalType.EXE, false)).meta(metaControls_).profile(0,
			Profile::getAltExeParam, Profile::setAltExeParam).but(b -> b.grab(mountingpointsList_, false)).build();

		Text alt2 = Chain.on(dosComposite).lbl(l -> l.key("dialog.profile.altexe", new Object[] {2})).txt(t -> t.horSpan(2)).meta(metaControls_).profile(1, Profile::getAltExeString,
			Profile::setAltExeFileLocation).text();
		Chain alt2Chain = Chain.on(dosComposite).lbl(l -> l).txt(t -> t).but(b -> b.browse(false, Button_.BrowseType.FILE, Button_.CanonicalType.EXE, false)).meta(metaControls_).profile(1,
			Profile::getAltExeParam, Profile::setAltExeParam).but(b -> b.grab(mountingpointsList_, false)).build();

		dosExpandItem_.setHeight(dosComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT).y);

		for (int i = 0; i < Profile.NR_OF_LINK_DESTINATIONS; i++) {
			linkBrowseButton_[i].setData(Button_.DATA_ALT_CONTROL, main_);
		}

		img1Chain.getButton().setData(Button_.DATA_ALT_CONTROL, main_);
		img2Chain.getButton().setData(Button_.DATA_ALT_CONTROL, img1_);
		img3Chain.getButton().setData(Button_.DATA_ALT_CONTROL, img1_);
		setupChain.getButton().setData(Button_.DATA_ALT_CONTROL, main_);
		alt1Chain.getButtons()[0].setData(Button_.DATA_CONTROL, new TextControl_(alt1));
		alt1Chain.getButtons()[1].setData(Button_.DATA_CONTROL, new TextControl_(alt1));
		alt1Chain.getButton().setData(Button_.DATA_ALT_CONTROL, main_);
		alt2Chain.getButtons()[0].setData(Button_.DATA_CONTROL, new TextControl_(alt2));
		alt2Chain.getButtons()[1].setData(Button_.DATA_CONTROL, new TextControl_(alt2));
		alt2Chain.getButton().setData(Button_.DATA_ALT_CONTROL, main_);

		if (multiEdit) {
			Stream.of(booterComposite.getChildren()).forEach(x -> x.setEnabled(false));
			Stream.of(dosComposite.getChildren()).forEach(x -> x.setEnabled(false));
		}
	}
}
