/*******************************************************************************
 * Copyright (c) 2005, 2008 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IBM Rational Software - Initial API and implementation
 *    Anton Leherbauer (Wind River Systems)
 *******************************************************************************/
package org.eclipse.cdt.ui.tests.DOMAST;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPathEditorInput;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionDelegate;
import org.eclipse.ui.editors.text.ILocationProvider;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.ui.texteditor.ITextEditor;

import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.ui.testplugin.CTestPlugin;

import org.eclipse.cdt.internal.ui.editor.CEditor;

/**
 * @author dsteffle
 */
public class ShowInDOMViewAction extends ActionDelegate implements
		IEditorActionDelegate {

	private static final String FIND_NODE_IN_AST_DOM_VIEW = "Find Node in AST DOM View"; //$NON-NLS-1$
	CEditor editor = null;
	IASTTranslationUnit tu = null;
	IViewPart view = null;
	String file = null;
	
	/* (non-Javadoc)
	 * @see org.eclipse.ui.IEditorActionDelegate#setActiveEditor(org.eclipse.jface.action.IAction, org.eclipse.ui.IEditorPart)
	 */
	public void setActiveEditor(IAction action, IEditorPart targetEditor) {
		if (targetEditor instanceof CEditor)
			editor = (CEditor)targetEditor;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.ui.actions.ActionDelegate#runWithEvent(org.eclipse.jface.action.IAction, org.eclipse.swt.widgets.Event)
	 */
	public void runWithEvent(IAction action, Event event) {
		TextSelection selection = null;
		
		if (editor != null &&
				editor.getSelectionProvider().getSelection() instanceof TextSelection) {
			selection = (TextSelection)editor.getSelectionProvider().getSelection();
		}
		if (selection != null) {
			if (!isFileInView()) {
				view = DOMAST.openDOMASTViewRunAction(editor, new FindDisplayNode(selection.getOffset(), selection.getLength()), FIND_NODE_IN_AST_DOM_VIEW);				
			} else {
				new FindDisplayNode(selection.getOffset(), selection.getLength()).run();
			}
		}
	}

	protected void showMessage(String message) {
		MessageDialog.openInformation(CTestPlugin.getStandardDisplay().getActiveShell(), DOMAST.VIEW_NAME, message);
	}
	
	private boolean isFileInView() {
		file= getInputFile(editor);
		
		if (file == null) return false;

		try {
			view = editor.getSite().getPage().showView(DOMAST.VIEW_ID);
		} catch (PartInitException pie) {}
		
		if (view instanceof DOMAST) {
			IContentProvider provider = ((DOMAST)view).getContentProvider();
			if (provider != null && provider instanceof DOMAST.ViewContentProvider) {
				tu = ((DOMAST.ViewContentProvider)provider).getTU();
				
				if (tu != null) {
					String fileName = null;
					
					// check if file is tu
					IASTNodeLocation[] locs = tu.getNodeLocations();
					for (int i=0; i<locs.length; i++) {
						if (locs[i] instanceof IASTFileLocation) {
							fileName = ((IASTFileLocation)locs[i]).getFileName();
						}
					}
					
					if (fileName != null && fileName.equals(file) ) {
						return true;
					}
					
					// check the #includes on the TU (i.e. check if selecting something from a header file shown in DOM View)
					IASTPreprocessorIncludeStatement[] includes = tu.getIncludeDirectives();
					for(int i=0; i<includes.length; i++) {
						if (includes[i].getPath().equals(file)) {
							return true;
						}
					}
				}
			}
		}

		
		return false;
	}

	/**
	 * Get the absolute file system location of the file open in the given editor.
	 * @param editor
	 * @return the absolute file system location or <code>null</code>
	 */
	private String getInputFile(ITextEditor editor) {
		IEditorInput input= editor.getEditorInput();
		if (input == null) {
			return null;
		}
		IFile file= ResourceUtil.getFile(input);
		if (file != null) {
			return file.getLocation().toOSString();
		}
		if (input instanceof IPathEditorInput) {
			IPath location= ((IPathEditorInput)input).getPath();
			if (location != null) {
				return location.toOSString();
			}
		}
		ILocationProvider locationProvider= (ILocationProvider)input.getAdapter(ILocationProvider.class);
		if (locationProvider != null) {
			IPath location= locationProvider.getPath(input);
			if (location != null) {
				return location.toOSString();
			}
		}
		return null;
	}

	private class FindDisplayNode implements Runnable {
		private static final String IAST_NODE_NOT_FOUND = "IASTNode not found for the selection. "; //$NON-NLS-1$
		private static final String IASTNode_NOT_FOUND = IAST_NODE_NOT_FOUND;
		int offset = 0;
		int length = 0;
		
		public FindDisplayNode(int offset, int length) {
			this.offset = offset;
			this.length = length;
		}
		
		/* (non-Javadoc)
		 * @see org.eclipse.jface.action.Action#run()
		 */
		public void run() {
			if (view instanceof DOMAST) {
				IContentProvider provider = ((DOMAST)view).getContentProvider();
				if (provider != null && provider instanceof DOMAST.ViewContentProvider) {
					tu = ((DOMAST.ViewContentProvider)provider).getTU();
					file = getInputFile(editor);
				}
			}
			
			// the selection is within a file currently shown in the DOM AST View
			if (tu != null && file != null && view instanceof DOMAST) {
				IASTNode node = tu.getNodeSelector(file).findNode(offset, length);
				if (node != null && ((DOMAST)view).getContentProvider() instanceof DOMAST.ViewContentProvider) {
					boolean success = ((DOMAST.ViewContentProvider)((DOMAST)view).getContentProvider()).findAndSelect(node, true); // use offsets when searching for node equality
                    if( ! success )
                        showMessage(IASTNode_NOT_FOUND);
				} else {
					showMessage(IASTNode_NOT_FOUND);
				}
			}
		}
	}
	
}
