package org.etsi.mts.tdl.wizards.importWizards;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;

import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.preference.FileFieldEditor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.Label;
import org.eclipse.ui.dialogs.WizardNewFileCreationPage;
import org.eclipse.xtext.util.StringInputStream;
import org.etsi.mts.tdl.json2tdl.JSONConverter;
import org.etsi.mts.tdl.openapi2tdl.next.ConverterNext;
import org.osgi.service.prefs.Preferences;


public class ImportWizardPage extends WizardNewFileCreationPage {
	
	protected FileFieldEditor editor;
	private boolean inline = false;
	private boolean copySource = false;
	private IPath sourcePath;
	LinkedHashMap<String, String> dataFormats = new LinkedHashMap<>();

	public ImportWizardPage(String pageName, IStructuredSelection selection) {
		super(pageName, selection);
		setTitle(pageName); //NON-NLS-1
		setDescription("Import data definitions from a file from the local file system into the workspace"); //NON-NLS-1
		loadDataFormat("org.etsi.mts.tdl.openapi2tdl.next", "OpenAPI", "*.yaml");
		loadDataFormat("org.etsi.mts.tdl.asn2tdl", "ASN.1", "*.asn1;*.asn");
		loadDataFormat("org.etsi.mts.tdl.json2tdl", "JSON", "*.json");
		loadDataFormat("org.etsi.mts.tdl.yang2tdl", "YANG", "*.yang");
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.dialogs.WizardNewFileCreationPage#createAdvancedControls(org.eclipse.swt.widgets.Composite)
	 */	
	protected void createAdvancedControls(Composite parent) {
		Composite fileSelectionArea = new Composite(parent, SWT.NONE);
		GridData fileSelectionData = new GridData(GridData.GRAB_HORIZONTAL
				| GridData.FILL_HORIZONTAL);
		fileSelectionArea.setLayoutData(fileSelectionData);

		GridLayout fileSelectionLayout = new GridLayout();
		fileSelectionLayout.numColumns = 3;
		fileSelectionLayout.makeColumnsEqualWidth = false;
		fileSelectionLayout.marginWidth = 0;
		fileSelectionLayout.marginHeight = 0;
		fileSelectionArea.setLayout(fileSelectionLayout);
		
		//DONE: ensure that is a valid path (not-empty and existing and having the right extension
		//DONE: store and pre-fill with last used -> consider expanding with injected preferences for other controls as well
		String lastUsed = "LAST_USED";
		Preferences preferences = InstanceScope.INSTANCE.getNode("org.etsi.mts.tdl.wizarads.import.data");

		editor = new FileFieldEditor("fileSelect","Select Data File: ",fileSelectionArea); //NON-NLS-1 //NON-NLS-2
		editor.getTextControl(fileSelectionArea).addModifyListener(e -> {
			setSourcePath(new Path(ImportWizardPage.this.editor.getStringValue()));
			if (getSourcePath().lastSegment()!=null && !getSourcePath().lastSegment().equals("null")) {
				preferences.put(lastUsed, getSourcePath().toOSString());
				setFileName(getSourcePath().lastSegment()+".tdltx"); //TODO: generalise
			}
		});
		editor.getTextControl(fileSelectionArea).setText(preferences.get(lastUsed, ""));
		
		//DONE: add option to copy source 
		//TODO: adapt extensions based on available bundles
		List<String> extensions = new ArrayList<String>(); 
		extensions.add(String.join(";",dataFormats.values()));
		extensions.addAll(dataFormats.values());
		editor.setFileExtensions(extensions.toArray(String[]::new));
		fileSelectionArea.moveAbove(null);

		
		Label labelCopy = new Label(fileSelectionArea, SWT.NONE);
        labelCopy.setText("Copy Data File:");
        Button buttonCopy = new Button(fileSelectionArea, SWT.CHECK);
        buttonCopy.setSelection(false);
        buttonCopy.addSelectionListener(SelectionListener.widgetSelectedAdapter(this::copyDataDefinitions));
		//fill empty cell
		new Label(fileSelectionArea, SWT.NONE);

		Label labelFlatten = new Label(fileSelectionArea, SWT.NONE);
		//TODO: for OpenAPI only?
        labelFlatten.setText("Import Inline Definitions:");
        //TODO: link and verify results
        Button buttonFlatten = new Button(fileSelectionArea, SWT.CHECK);
        buttonFlatten.setSelection(false);
        buttonFlatten.addSelectionListener(SelectionListener.widgetSelectedAdapter(this::flattenDataDefinitions));
//        fill empty cell
		new Label(fileSelectionArea, SWT.NONE);
	}
	
	private void loadDataFormat(String bundleName, String label, String extension) {
		if (Platform.getBundle(bundleName) != null) {
			dataFormats.put(label, extension);
		}
	}

	
	 /* (non-Javadoc)
	 * @see org.eclipse.ui.dialogs.WizardNewFileCreationPage#createLinkTarget()
	 */
	protected void createLinkTarget() {
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.dialogs.WizardNewFileCreationPage#getInitialContents()
	 */
	protected InputStream getInitialContents() {
		try {
			if (editor.getStringValue().endsWith(".yaml")) {
				//YAML
				System.out.println("From OpenAPI YAML...");
//				IWorkspace workspace = ResourcesPlugin.getWorkspace();
//				IWorkspaceRoot root = workspace.getRoot();
//				IPath location = root.getLocation();
				String content = ConverterNext.processToString(editor.getStringValue(), 
//						editor.getStringValue()+".tdltx",
//						location.append(getContainerFullPath()).append(getFileName()).toOSString(),
						getContainerFullPath().append(getFileName()).toOSString(),
						"SOURCE_MAPPING", 
						"TARGET_MAPPING",
						inline
						);
				return new StringInputStream(content);
			} else if (editor.getStringValue().endsWith(".json")) {
				System.out.println("From JSON...");
				//JSON
//				JsonSyntaxException e;
//				AbstractTranslator translator = new JSON2TDLTranslator();
//				Resource tr = TDLHelper.create(editor.getStringValue()+"-generated.tdltx");
//				translator.setTargetResource(tr);
//				translator.initTargetResource(translator.cleanName(editor.getStringValue()));
//				translator.translate(editor.getStringValue());
//				String content = TDLHelper.getText(tr);
				String content = JSONConverter.processToString(editor.getStringValue(), editor.getStringValue()+"-generated.tdltx");
				return new StringInputStream(content);
			} else {
				return null;
			}
//			return new FileInputStream(new File(editor.getStringValue()));
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.dialogs.WizardNewFileCreationPage#getNewFileLabel()
	 */
	protected String getNewFileLabel() {
		return "Imported Package Name:"; //NON-NLS-1
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.dialogs.WizardNewFileCreationPage#validateLinkedResource()
	 */
	protected IStatus validateLinkedResource() {
		return Status.OK_STATUS;
	}

	@Override
	protected boolean validatePage() {
		boolean validatePage = super.validatePage();
		//basic check for referenced data file
		if (this.editor != null) {
			IPath sourcePath = Path.fromOSString(this.editor.getStringValue());
			boolean exists = sourcePath.toFile().exists();
			if (!exists) {
				setErrorMessage("The selected data file path is not valid.");
			}
			return exists && validatePage;
		} else {
			return false;
		}
	}
	
	private void flattenDataDefinitions(SelectionEvent e) {
		inline = ((Button) e.getSource()).getSelection();
	}

	private void copyDataDefinitions(SelectionEvent e) {
		setCopySource(((Button) e.getSource()).getSelection());
	}

	public boolean isCopySource() {
		return copySource;
	}

	public void setCopySource(boolean copySource) {
		this.copySource = copySource;
	}

	public IPath getSourcePath() {
		return sourcePath;
	}

	public void setSourcePath(IPath sourcePath) {
		this.sourcePath = sourcePath;
	}
}
