package org.etsi.mts.tdl.execution.java.eclipse.ui;

import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.StringButtonFieldEditor;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IWorkbenchPropertyPage;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import org.etsi.mts.tdl.execution.java.codegen.Settings;

public class PropertyPage extends FieldEditorPreferencePage implements IWorkbenchPropertyPage {

	public static final String PREFERENCE_SCOPE = "org.etsi.mts.tdl.execution";

	private static final List<String> REQUIRED_SETTINGS = Arrays.asList(new String[] { Settings.OUTPUT_DIR, Settings.INJECTOR });

	protected IAdaptable element;

	protected Map<FieldEditor, String> fields = new Hashtable<FieldEditor, String>();

	public PropertyPage() {
		super(GRID);
	}

	@Override
	public IAdaptable getElement() {
		return element;
	}

	@Override
	public void setElement(IAdaptable element) {
		this.element = element;
	}

	@Override
	protected IPreferenceStore doGetPreferenceStore() {
		ProjectScope ps = new ProjectScope((IProject) this.element);
		return new ScopedPreferenceStore(ps, PREFERENCE_SCOPE);
	}

	@Override
	protected void initialize() {
		for (FieldEditor e : fields.keySet()) {
			String value = getPreferenceStore().getString(e.getPreferenceName());
			fields.put(e, value);
			initialize(e.getPreferenceName(), value, e);
		}
		super.initialize();
	}

	protected void initialize(String name, String value, FieldEditor e) {
	}

	@Override
	protected void addField(FieldEditor editor) {
		super.addField(editor);
		fields.put(editor, "");
	}

	@Override
	public void propertyChange(PropertyChangeEvent event) {
		super.propertyChange(event);
		if (event.getProperty().equals(FieldEditor.VALUE)) {
			FieldEditor e = (FieldEditor) event.getSource();

			String name = e.getPreferenceName();
			String value = event.getNewValue().toString();

			fields.put(e, value);

			initialize(name, value, e);

			checkState();
		}
	}

	@Override
	protected void checkState() {
		setErrorMessage(null);
		super.checkState();
	}

	@Override
	protected void createFieldEditors() {

		Composite parent = getFieldEditorParent();
		FieldEditor outDir = new ContainerFieldEditor(Settings.OUTPUT_DIR, "Output folder", parent) {
			@Override
			public boolean isValid() {
				return PropertyPage.this.isValid(this) && doCheckState();
			}
		};
		addField(outDir);

		parent = getFieldEditorParent();
		StringFieldEditor outPackage = new StringFieldEditor(Settings.PACKAGE, "Package", parent);
		addField(outPackage);

		parent = getFieldEditorParent();
		StringFieldEditor injector = new StringFieldEditor(Settings.INJECTOR, "Guice module", parent);
		addField(injector);

		parent = getFieldEditorParent();
		StringFieldEditor dateFormat = new StringFieldEditor(Settings.DATE_FORMAT, "Date format", parent);
		addField(dateFormat);

		parent = getFieldEditorParent();
		StringFieldEditor useMapping = new StringFieldEditor(Settings.USE_MAPPING, "Mapping for TRI", parent);
		addField(useMapping);

		parent = getFieldEditorParent();
		BooleanFieldEditor unmappedData = new BooleanFieldEditor(Settings.UNMAPPED_DATA, "Use unmapped data", parent);
		addField(unmappedData);

	}

	private boolean isValid(FieldEditor e) {
		String name = e.getPreferenceName();
		String value = fields.get(e);

		if (REQUIRED_SETTINGS.contains(name)) {
			if (value.isEmpty()) {
				setErrorMessage(String.format("%s must be selected!", e.getLabelText()));
				return false;
			}
		}

		return true;
	}

}

class ContainerFieldEditor extends StringButtonFieldEditor {

	public ContainerFieldEditor(String name, String label, Composite parent) {
		super(name, label, parent);
	}

	@Override
	protected String changePressed() {

		IContainer root = ResourcesPlugin.getWorkspace().getRoot();
		ContainerSelectionDialog d = new ContainerSelectionDialog(getShell(), root, true, "Select output folder");
		int result = d.open();
		if (result == 0) {
			Object[] dir = d.getResult();
			if (dir.length > 0)
				return dir[0].toString();
		}
		return null;
	}

	@Override
	protected boolean doCheckState() {
		String pathText = getTextControl().getText();
		IPath path = new Path(pathText);
		IContainer root = ResourcesPlugin.getWorkspace().getRoot();
		IFolder f;
		try {
			f = root.getFolder(path);
		} catch (IllegalArgumentException e) {
			setErrorMessage(e.getMessage());
			return false;
		}
		if (!f.exists())
			setErrorMessage(pathText + " does not exist!");
		return f != null && f.exists();
	}

}
