/*******************************************************************************
 * Copyright (c) 2007, 2010 Nokia 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:
 *     Nokia - initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.debug.internal.ui.actions;


import org.eclipse.cdt.debug.internal.core.CRequest;
import org.eclipse.cdt.debug.internal.core.ICWatchpointTarget;
import org.eclipse.cdt.debug.ui.CDebugUIPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.progress.WorkbenchJob;

/**
 * Invoked when user right clicks on an element in the Variables or Expressions
 * view and selects 'Add Watchpoint (C/C++)'
 */
public class AddWatchpointOnVariableActionDelegate extends AddWatchpointActionDelegate implements IObjectActionDelegate {

	/** The target variable/expression */
	private ICWatchpointTarget fVar;
	
	/** The view where fVar was selected */ 
	private IWorkbenchPart fActivePart;
	
	/**
	 * Constructor
	 */
	public AddWatchpointOnVariableActionDelegate() {
		super();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart)
	 */
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		fActivePart = targetPart;
	}

	private static class GetSizeRequest extends CRequest implements ICWatchpointTarget.GetSizeRequest {
		int fSize = -1;
		public int getSize() {
			return fSize;
		}
		public void setSize(int size) {
			fSize = size;
		}
	};
	
	/* (non-Javadoc)
	 * @see org.eclipse.cdt.debug.internal.ui.actions.AddWatchpointActionDelegate#run(org.eclipse.jface.action.IAction)
	 */
	public void run(IAction action) {
		if (fVar == null) {
			return;
		}
		
		final String expr = fVar.getExpression();
		if (expr == null) {
			assert false : "how are we getting an empty expression?"; //$NON-NLS-1$
			return;
		}

		// Getting the size of the variable/expression is an asynchronous
		// operation...or at least the API is (the CDI implementation reacts
		// synchronously)
		final ICWatchpointTarget.GetSizeRequest request = new GetSizeRequest() {
			public void done() {
				if (isSuccess()) {
					// Now that we have the size, put up a dialog to create the watchpoint
					final int size = getSize();
					assert size > 0 : "unexpected variale/expression size"; //$NON-NLS-1$
					WorkbenchJob job = new WorkbenchJob("open watchpoint dialog") { //$NON-NLS-1$
						@Override
						public IStatus runInUIThread(IProgressMonitor monitor) {
							AddWatchpointDialog dlg = new AddWatchpointDialog(CDebugUIPlugin.getActiveWorkbenchShell(), 
									getMemorySpaceManagement());
							dlg.setExpression(expr);
							dlg.initializeRange(false, Integer.toString(size));
							if (dlg.open() == Window.OK) {
								addWatchpoint(dlg.getWriteAccess(), dlg.getReadAccess(), dlg.getExpression(), dlg.getMemorySpace(), dlg.getRange());
							}
							return Status.OK_STATUS;
						}
					};
					job.setSystem(true);
					job.schedule();
				}
				else  {
					WorkbenchJob job = new WorkbenchJob("watchpoint error") { //$NON-NLS-1$
						@Override
						public IStatus runInUIThread(IProgressMonitor monitor) {
							if (fActivePart != null) {
								ErrorDialog.openError( fActivePart.getSite().getWorkbenchWindow().getShell(), ActionMessages.getString( "AddWatchpointOnVariableActionDelegate.Error_Dlg_Title" ), ActionMessages.getString( "AddWatchpointOnVariableActionDelegate.No_Element_Size" ), getStatus() ); //$NON-NLS-1$ //$NON-NLS-2$
							}
							return Status.OK_STATUS;
						}
					};
					job.setSystem(true);
					job.schedule();
				}
			}
		};
		fVar.getSize(request);
	}
	
	private class CanCreateWatchpointRequest extends CRequest implements ICWatchpointTarget.CanCreateWatchpointRequest {
		boolean fCanCreate;
		public boolean getCanCreate() {
			return fCanCreate;
		}
		public void setCanCreate(boolean value) {
			fCanCreate = value;
		}
	};

	/**
	 * Record the target variable/expression
	 * 
	 * @see org.eclipse.ui.actions.ActionDelegate#selectionChanged(org.eclipse.jface.action.IAction,
	 *      org.eclipse.jface.viewers.ISelection)
	 */
	public void selectionChanged(final IAction action, ISelection selection) {
		fVar = null;
		if (selection == null || selection.isEmpty()) {
			action.setEnabled(false);
			return;
		}
		if (selection instanceof TreeSelection) {
			Object obj = ((TreeSelection)selection).getFirstElement();
			fVar = (ICWatchpointTarget)DebugPlugin.getAdapter(obj, ICWatchpointTarget.class);
			if (fVar != null) {
				final ICWatchpointTarget.CanCreateWatchpointRequest request = new CanCreateWatchpointRequest() {
					public void done() {
						action.setEnabled(getCanCreate());
					}
				};
				fVar.canSetWatchpoint(request);
				return;
			}
			assert false : "action should not have been available for object " + obj; //$NON-NLS-1$
		}
		else if (selection instanceof StructuredSelection) {
			// Not sure why, but sometimes we get an extraneous empty StructuredSelection. Seems harmless enough
			assert ((StructuredSelection)selection).getFirstElement() == null : "action installed in unexpected type of view/part"; //$NON-NLS-1$
		}
		else {
			assert false : "action installed in unexpected type of view/part"; //$NON-NLS-1$
		}
		action.setEnabled(false);
	}
}
