package jp.ac.kyutech.ai.ylab.shiva.nativecapable.plugin.exportwizard;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;

import jp.ac.kyutech.ai.ylab.shiva.nativecapable.plugin.Utils;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogPage;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalListener;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.IControlContentAdapter;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
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.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;

/**
 * The "New" wizard page allows setting the container for the new project as
 * well as the source folder.
 */

public class NativeCapableExportWizardCreationPage extends WizardPage {

	final String TYPE_FQCN = "jp.ac.kyutech.ai.ylab.shiva.utils.nativecapable.NativeCapableModule";

	final String TYPE_FQCN_OBJECT = "java.lang.Object";

	private Text targetModuleText;

	private Button createApplicationCheckButton;

	private Button createAppletCheckButton;

	private Button packageAddButton;

	private Button packageRemoveButton;

	private Button packageDefaultButton;

	private Button delegateTargetsRadioButton;

	private Button loadTargetsRadioButton;

	private List targetList;

	private ISelection selection;

	private NativeCapableExportWizardConfigPage pageConfig;

	private void setTextContentAdapterToTargetClassText(final Text text) {

		IControlContentAdapter contentAdapter = new TextContentAdapter();
		IContentProposalProvider provider = new IContentProposalProvider() {
			@Override
			public IContentProposal[] getProposals(String contents,
					final int position) {
				final IType rootType;
				final IType objectType;

				IResource resource = (IResource) Utils
						.getSelectedResource(selection);
				IProject project = resource.getProject();
				IJavaProject javaProject = JavaCore.create(project);

				try {
					rootType = javaProject.findType(TYPE_FQCN);
					objectType = javaProject.findType(TYPE_FQCN_OBJECT);
				} catch (JavaModelException e) {
					return new IContentProposal[0];
				}

				IJavaSearchScope scope = null;

				SearchEngine engine = new SearchEngine();
				SearchPattern pattern = null;
				if (contents.length() > 0) {
					try {
						scope = SearchEngine.createHierarchyScope(rootType);
					} catch (JavaModelException e) {
						return new IContentProposal[0];
					}
					pattern = SearchPattern.createPattern(contents,
							IJavaSearchConstants.TYPE,
							IJavaSearchConstants.DECLARATIONS,
							SearchPattern.R_PREFIX_MATCH);
				} else {
					try {
						scope = SearchEngine.createHierarchyScope(rootType);
					} catch (JavaModelException e) {
						return new IContentProposal[0];
					}
					pattern = SearchPattern.createPattern("*",
							IJavaSearchConstants.TYPE,
							IJavaSearchConstants.DECLARATIONS,
							SearchPattern.R_PATTERN_MATCH);
				}

				final Collection<IContentProposal> cpList = new ArrayList<IContentProposal>();
				SearchRequestor requester = new SearchRequestor() {
					@Override
					public void acceptSearchMatch(SearchMatch match)
							throws CoreException {
						Object o = match.getElement();
						if (o instanceof IType) {
							IType type = (IType) o;
							if (type.equals(rootType)
									|| type.equals(objectType)) {
								return;
							}

							String content = type.getFullyQualifiedName();
							String label = type.getElementName() + " - "
									+ type.getFullyQualifiedName();
							IContentProposal icp = new ContentProposal(content,
									position + content.length(), null, label);
							cpList.add(icp);
						}
					}
				};

				try {
					engine.search(pattern,
							new SearchParticipant[] { SearchEngine
									.getDefaultSearchParticipant() }, scope,
							requester, null);
				} catch (CoreException e) {
					e.printStackTrace();
				}

				IContentProposal[] icps = new IContentProposal[cpList.size()];
				cpList.toArray(icps);
				return icps;
			}
		};
		final ContentAssistCommandAdapter ca = new ContentAssistCommandAdapter(
				text, contentAdapter, provider, null, new char[] { '$', '.' },
				true);
		ca.addContentProposalListener(new IContentProposalListener() {
			@Override
			public void proposalAccepted(IContentProposal proposal) {
				text.setText(proposal.getContent());
			}
		});

		// TODO:return specific image
		if (false) {
			ca.setLabelProvider(new LabelProvider() {
				@Override
				public Image getImage(Object element) {
					// IContentProposal proposal = (IContentProposal) element;
					return super.getImage(element);
				}

				@Override
				public String getText(Object element) {
					IContentProposal proposal = (IContentProposal) element;
					return proposal.getLabel() == null ? proposal.getContent()
							: proposal.getLabel();
				}
			});
		}

	}

	/**
	 * Constructor for NyARToolkitProjectNewWizardPage.
	 * 
	 * @param pageName
	 */
	public NativeCapableExportWizardCreationPage(ISelection selection,
			NativeCapableExportWizardConfigPage pageConfig) {
		super("Export Page");
		setTitle("Native Capable Export Wizard");
		setDescription("This wizard exports native capables.");
		this.selection = selection;

		this.pageConfig = pageConfig;
	}

	/**
	 * @see IDialogPage#createControl(Composite)
	 */
	public void createControl(Composite parent) {
		Composite container = new Composite(parent, SWT.NULL);
		container.setLayout(new GridLayout(4, true));

		Label label = new Label(container, SWT.NULL);
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalIndent = 9;
		label.setLayoutData(gd);
		label.setText("&Module:");

		targetModuleText = new Text(container, SWT.BORDER | SWT.SINGLE);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 3;
		gd.verticalIndent = 9;
		targetModuleText.setLayoutData(gd);
		targetModuleText.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				dialogChanged();
			}
		});
		setTextContentAdapterToTargetClassText(targetModuleText);

		label = new Label(container, SWT.NULL);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalIndent = 9;
		label.setLayoutData(gd);
		label.setText("&Create:");

		createApplicationCheckButton = new Button(container, SWT.CHECK);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalIndent = 9;
		createApplicationCheckButton.setLayoutData(gd);
		createApplicationCheckButton.setText("Application");
		createApplicationCheckButton.setSelection(true);
		createApplicationCheckButton
				.addSelectionListener(new SelectionListener() {
					@Override
					public void widgetDefaultSelected(SelectionEvent e) {
						dialogChanged();
					}

					public void widgetSelected(SelectionEvent e) {
						dialogChanged();
					};
				});

		createAppletCheckButton = new Button(container, SWT.CHECK);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalIndent = 9;
		createAppletCheckButton.setLayoutData(gd);
		createAppletCheckButton.setText("Applet");
		createAppletCheckButton.setSelection(true);
		createAppletCheckButton.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				dialogChanged();
			}

			public void widgetSelected(SelectionEvent e) {
				dialogChanged();
			};
		});

		Label sep = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 4;
		gd.verticalIndent = 9;
		sep.setLayoutData(gd);

		// ----------Packages--------------
		label = new Label(container, SWT.NULL);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalSpan = 3;
		gd.verticalIndent = 9;
		gd.verticalAlignment = SWT.TOP;
		label.setLayoutData(gd);
		label.setText("&Targets:");

		targetList = new List(container, SWT.BORDER);
		gd = new GridData(GridData.FILL_BOTH);
		gd.horizontalSpan = 2;
		gd.verticalSpan = 3;
		gd.verticalIndent = 9;
		targetList.setLayoutData(gd);

		packageAddButton = new Button(container, SWT.PUSH);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalSpan = 1;
		gd.verticalIndent = 9;
		gd.verticalAlignment = SWT.TOP;
		packageAddButton.setLayoutData(gd);
		packageAddButton.setText("&Add");
		packageAddButton.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				// this will not be called.
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				TargetAdditionDialog dialog = new TargetAdditionDialog(
						getShell());
				dialog.open();
			}
		});
		packageRemoveButton = new Button(container, SWT.PUSH);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalSpan = 1;
		gd.verticalIndent = 3;
		gd.verticalAlignment = SWT.TOP;
		packageRemoveButton.setLayoutData(gd);
		packageRemoveButton.setText("&Remove");
		packageRemoveButton.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				// this will not be called.
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				if (targetList.getSelectionCount() <= 0) {
					return;
				}
				targetList.remove(targetList.getSelectionIndex());

			}
		});

		packageDefaultButton = new Button(container, SWT.PUSH);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalSpan = 1;
		gd.verticalIndent = 3;
		gd.verticalAlignment = SWT.TOP;
		packageDefaultButton.setLayoutData(gd);
		packageDefaultButton.setText("&Default");
		packageDefaultButton.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				// this will not be called.
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				setDefault();
			}
		});

		label = new Label(container, SWT.NULL);
		label.setText("&Strategy:");
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalIndent = 9;
		label.setLayoutData(gd);
		delegateTargetsRadioButton = new Button(container, SWT.RADIO);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalIndent = 9;
		delegateTargetsRadioButton.setLayoutData(gd);
		delegateTargetsRadioButton.setText("Delegate Targets");
		delegateTargetsRadioButton.setSelection(true);
		loadTargetsRadioButton = new Button(container, SWT.RADIO);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan = 1;
		gd.verticalIndent = 9;
		loadTargetsRadioButton.setLayoutData(gd);
		loadTargetsRadioButton.setText("Load Targets");

		delegateTargetsRadioButton
				.addSelectionListener(new SelectionListener() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						loadTargetsRadioButton
								.setSelection(!delegateTargetsRadioButton
										.getSelection());
					}

					@Override
					public void widgetDefaultSelected(SelectionEvent e) {
						// never been called
					}
				});
		loadTargetsRadioButton.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				delegateTargetsRadioButton.setSelection(!loadTargetsRadioButton
						.getSelection());
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				// never been called
			}
		});

		initialize();
		dialogChanged();
		setControl(container);
	}

	private void setDefault() {
		if (delegateTargetsRadioButton.getSelection()) {
			targetList.removeAll();
			targetList.add("java");
			targetList.add("sun.reflect");
			targetList.add("javax.swing");
			targetList.add("javax.xml");
			targetList.add("org.w3c.dom");
			targetList.add("sun.java2d");
			targetList.add("sun.awt");
			targetList.add("com.sun.org.apache.xerces");

		} else if (loadTargetsRadioButton.getSelection()) {
			targetList.removeAll();
			targetList.add("javax.media");
			targetList.add("com.sun.j3d");
			targetList.add("com.sun.opengl");
			targetList.add("com.sun.media");
			targetList.add("jp.nyatla");
			targetList.add("jp.ac.kyutech.ai.ylab.shiva.utils.nativecapable");
		}

	}

	/**
	 * Tests if the current workbench selection is a suitable container to use.
	 */

	private void initialize() {
		if (selection != null && selection.isEmpty() == false
				&& selection instanceof IStructuredSelection) {
			IStructuredSelection ssel = (IStructuredSelection) selection;
			if (ssel.size() > 1)
				return;
			Object obj = ssel.getFirstElement();
			if (obj instanceof IResource) {
				IContainer container;
				if (obj instanceof IContainer) {
					container = (IContainer) obj;
				} else {
					container = ((IResource) obj).getParent();
				}
				targetModuleText.setText(container.getFullPath().toString());
			}
		}

		setDefault();

	}

	// /**
	// * Uses the standard container selection dialog to choose the new value
	// for
	// * the container field.
	// */
	//
	// private void handleBrowse() {
	// ContainerSelectionDialog dialog = new ContainerSelectionDialog(
	// getShell(), ResourcesPlugin.getWorkspace().getRoot(), false,
	// "Select new file container");
	// if (dialog.open() == ContainerSelectionDialog.OK) {
	// Object[] result = dialog.getResult();
	// if (result.length == 1) {
	// projectNameText.setText(((Path) result[0]).toString());
	// }
	// }
	// }

	/**
	 * Ensures that both text fields are set.
	 */
	private void dialogChanged() {

		if (getTargetModule().length() == 0) {
			updateStatus("Module must be specified");
			return;
		}

		if (!createAppletCheckButton.getSelection()
				&& !createApplicationCheckButton.getSelection()) {
			updateStatus("At least, Applet or Appilcation must be checked");
			return;
		}

		updateStatus(null);
	}

	@Override
	public IWizardPage getNextPage() {

		if (pageConfig != null) {
			pageConfig.updateControl(isCreateApplet(), isCreateApplication());
		}

		return super.getNextPage();
	}

	private void updateStatus(String message) {
		setErrorMessage(message);
		setPageComplete(message == null);
	}

	public class TargetAdditionDialog extends Dialog {

		private Text text;

		private List matchingList;

		private Collection<String> targets;

		public TargetAdditionDialog(Shell parent) {
			super(parent);
			targets = new ArrayList<String>();
		}

		protected Point getInitialSize() {
			return new Point(400, 300);
		}

		protected void configureShell(Shell newShell) {
			super.configureShell(newShell);
			newShell.setText("Add Target Packages");
		}

		protected Control createDialogArea(Composite parent) {
			Composite composite = (Composite) super.createDialogArea(parent);

			Label l = new Label(composite, SWT.NULL);
			l.setText("&Choose Package");
			l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

			text = new Text(composite, SWT.BORDER | SWT.SINGLE);
			text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			text.addModifyListener(new ModifyListener() {
				@Override
				public void modifyText(ModifyEvent e) {
					searchPackages();
				}
			});

			l = new Label(composite, SWT.NULL);
			l.setText("&Matching Items");
			l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

			matchingList = new List(composite, SWT.BORDER);
			matchingList.setLayoutData(new GridData(GridData.FILL_BOTH));
			matchingList.addMouseListener(new MouseAdapter() {
				@Override
				public void mouseDoubleClick(MouseEvent e) {
					String strs = matchingList.getSelection()[0];
					if (!Arrays.asList(targetList.getItems()).contains(strs)) {
						targetList.add(strs);
						targets.add(strs);
						searchPackages();
					}
				}
			});

			return composite;
		}

		@Override
		protected void cancelPressed() {
			super.cancelPressed();
			for (String str : targets) {
				targetList.remove(str);
			}
		}

		private void searchPackages() {
			IJavaSearchScope scope = SearchEngine.createWorkspaceScope();

			String contents = text.getText();

			SearchEngine engine = new SearchEngine();
			SearchPattern pattern = SearchPattern.createPattern(contents + "*",
					IJavaSearchConstants.PACKAGE,
					IJavaSearchConstants.DECLARATIONS,
					SearchPattern.R_PREFIX_MATCH
							| SearchPattern.R_PATTERN_MATCH);

			final ArrayList<String> cpList = new ArrayList<String>();
			SearchRequestor requester = new SearchRequestor() {
				@Override
				public void acceptSearchMatch(SearchMatch match)
						throws CoreException {
					Object o = match.getElement();
					if (o instanceof IPackageFragment) {
						IPackageFragment type = (IPackageFragment) o;
						String content = type.getElementName();

						String[] items = targetList.getItems();
						for (String item : items) {
							if (content.equals(item)
									|| content.startsWith(item + ".")) {
								return;
							}
						}
						cpList.add(content);

					}
				}
			};

			try {
				engine.search(pattern, new SearchParticipant[] { SearchEngine
						.getDefaultSearchParticipant() }, scope, requester,
						null);
			} catch (CoreException e2) {
				e2.printStackTrace();
			}

			matchingList.removeAll();
			Collections.sort(cpList);
			for (String str : cpList) {
				matchingList.add(str);
			}

		}

		// TODO:return specific image
		// if (false) {
		// ca.setLabelProvider(new LabelProvider() {
		// @Override
		// public Image getImage(Object element) {
		// // IContentProposal proposal = (IContentProposal)
		// // element;
		// return super.getImage(element);
		// }
		//
		// @Override
		// public String getText(Object element) {
		// IContentProposal proposal = (IContentProposal) element;
		// return proposal.getLabel() == null ? proposal
		// .getContent() : proposal.getLabel();
		// }
		// });
		// }
	}

	public String[] getTargetList() {
		return targetList.getItems();
	}

	public String getTargetModule() {
		return targetModuleText.getText();
	}

	public boolean isDelegate() {
		if (delegateTargetsRadioButton.getSelection()) {
			return true;
		} else {
			return false;
		}
	}

	public boolean isCreateApplet() {
		return createAppletCheckButton.getSelection();
	}

	public boolean isCreateApplication() {
		return createApplicationCheckButton.getSelection();
	}
}