/*******************************************************************************
 * Copyright (c) 2004, 2015 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 Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.debug.ui;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.debug.internal.ui.SWTFactory;
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.jdt.internal.debug.core.logicalstructures.JavaLogicalStructure;
import org.eclipse.jdt.internal.debug.ui.contentassist.DynamicTypeContext;
import org.eclipse.jdt.internal.debug.ui.contentassist.DynamicTypeContext.ITypeProvider;
import org.eclipse.jdt.internal.debug.ui.contentassist.JavaDebugContentAssistProcessor;
import org.eclipse.jdt.internal.debug.ui.display.DisplayViewerConfiguration;
import org.eclipse.jdt.ui.IJavaElementSearchConstants;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jdt.ui.text.IJavaPartitions;
import org.eclipse.jdt.ui.text.JavaTextTools;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.StatusDialog;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
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.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;

/**
 * A dialog that allows users to create/edit logical structures.
 */
public class EditLogicalStructureDialog extends StatusDialog implements Listener, ISelectionChangedListener, IDocumentListener, ITypeProvider {

    public class AttributesContentProvider implements IStructuredContentProvider {

        private final List<String[]> fVariables;

        public  AttributesContentProvider(String[][] variables) {
            fVariables = new ArrayList<String[]>();
            for (int i = 0; i < variables.length; i++) {
                String[] variable = new String[2];
                variable[0] = variables[i][0];
                variable[1] = variables[i][1];
                fVariables.add(variable);
            }
        }

        /* (non-Javadoc)
		 * @see org.eclipse.jface.viewers.IContentProvider#dispose()
		 */
        @Override
        public void dispose() {
        }

        /* (non-Javadoc)
		 * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
		 */
        @Override
        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }

        /* (non-Javadoc)
		 * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
		 */
        @Override
        public Object[] getElements(Object inputElement) {
            return getElements();
        }

        /**
		 * Returns the attributes.
		 * @return the elements
		 */
        public String[][] getElements() {
            return fVariables.toArray(new String[fVariables.size()][]);
        }

        /**
		 * Adds the given attributes.
		 * @param newAttribute the new attribute
		 */
        public void add(String[] newAttribute) {
            fVariables.add(newAttribute);
        }

        /**
		 * Remove the given attributes
		 * @param list the list 
		 */
        public void remove(List<String[]> list) {
            fVariables.removeAll(list);
        }

        /**
		 * Moves the given attributes up in the list.
		 * @param list the list
		 */
        public void up(List<String[]> list) {
            for (Iterator<String[]> iter = list.iterator(); iter.hasNext(); ) {
                String[] variable = iter.next();
                int index = fVariables.indexOf(variable);
                fVariables.remove(variable);
                fVariables.add(index - 1, variable);
            }
        }

        /**
		 * Moves the given attributes down int the list.
		 * @param list the list
		 */
        public void down(List<String[]> list) {
            for (Iterator<String[]> iter = list.iterator(); iter.hasNext(); ) {
                String[] variable = iter.next();
                int index = fVariables.indexOf(variable);
                fVariables.remove(variable);
                fVariables.add(index + 1, variable);
            }
        }
    }

    public class AttributesLabelProvider extends LabelProvider {

        @Override
        public String getText(Object element) {
            return ((String[]) element)[0];
        }
    }

    private final JavaLogicalStructure fLogicalStructure;

    private Text fQualifiedTypeNameText;

    private Text fDescriptionText;

    private TableViewer fAttributeListViewer;

    private Button fSubTypeButton;

    private Button fValueButton;

    private Button fVariablesButton;

    private Button fAttributeUpButton;

    private Button fAttributeDownButton;

    private JDISourceViewer fSnippetViewer;

    private Document fSnippetDocument;

    private Button fBrowseTypeButton;

    private Button fAttributeAddButton;

    private Button fAttributeRemoveButton;

    private Text fAttributeNameText;

    private Composite fAttributesContainer;

    private Group fCodeGroup;

    private Composite fParentComposite;

    private AttributesContentProvider fAttributesContentProvider;

    private String fValueTmp;

    private IStructuredSelection fCurrentAttributeSelection;

    private IType fType;

    private boolean fTypeSearched = false;

    private DisplayViewerConfiguration fViewerConfiguration;

    private IHandlerActivation fHandlerActivation;

    public  EditLogicalStructureDialog(Shell parentShell, JavaLogicalStructure logicalStructure) {
        super(parentShell);
        setShellStyle(getShellStyle() | SWT.MAX | SWT.RESIZE);
        if (logicalStructure.getQualifiedTypeName().length() == 0) {
            setTitle(DebugUIMessages.EditLogicalStructureDialog_32);
        } else {
            setTitle(DebugUIMessages.EditLogicalStructureDialog_31);
        }
        fLogicalStructure = logicalStructure;
    }

    /* (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
	 */
    @Override
    protected Control createDialogArea(Composite parent) {
        IWorkbench workbench = PlatformUI.getWorkbench();
        workbench.getHelpSystem().setHelp(parent, IJavaDebugHelpContextIds.EDIT_LOGICAL_STRUCTURE_DIALOG);
        fParentComposite = parent;
        IHandler handler = new AbstractHandler() {

            @Override
            public Object execute(ExecutionEvent event) throws ExecutionException {
                if (fSnippetViewer.canDoOperation(ISourceViewer.CONTENTASSIST_PROPOSALS) && fSnippetViewer.getControl().isFocusControl()) {
                    findCorrespondingType();
                    fSnippetViewer.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
                }
                return null;
            }
        };
        IHandlerService handlerService = workbench.getAdapter(IHandlerService.class);
        fHandlerActivation = handlerService.activateHandler(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, handler);
        Composite container = SWTFactory.createComposite(parent, parent.getFont(), 1, 1, GridData.FILL_BOTH);
        Composite typeNameDescriptionContainer = SWTFactory.createComposite(container, container.getFont(), 2, 1, GridData.FILL_HORIZONTAL);
        SWTFactory.createLabel(typeNameDescriptionContainer, DebugUIMessages.EditLogicalStructureDialog_0, 2);
        fQualifiedTypeNameText = SWTFactory.createSingleText(typeNameDescriptionContainer, 1);
        fQualifiedTypeNameText.addListener(SWT.Modify, this);
        fBrowseTypeButton = SWTFactory.createPushButton(typeNameDescriptionContainer, DebugUIMessages.EditLogicalStructureDialog_1, DebugUIMessages.EditLogicalStructureDialog_25, null);
        fBrowseTypeButton.addListener(SWT.Selection, this);
        SWTFactory.createLabel(typeNameDescriptionContainer, DebugUIMessages.EditLogicalStructureDialog_2, 2);
        fDescriptionText = SWTFactory.createSingleText(typeNameDescriptionContainer, 2);
        fDescriptionText.addListener(SWT.Modify, this);
        fSubTypeButton = SWTFactory.createCheckButton(typeNameDescriptionContainer, DebugUIMessages.EditLogicalStructureDialog_3, null, false, 1);
        fSubTypeButton.setToolTipText(DebugUIMessages.EditLogicalStructureDialog_26);
        Group radioContainer = SWTFactory.createGroup(container, DebugUIMessages.EditLogicalStructureDialog_33, 1, 1, GridData.FILL_HORIZONTAL);
        fValueButton = SWTFactory.createRadioButton(radioContainer, DebugUIMessages.EditLogicalStructureDialog_4);
        fValueButton.addListener(SWT.Selection, this);
        fVariablesButton = SWTFactory.createRadioButton(radioContainer, DebugUIMessages.EditLogicalStructureDialog_5);
        fAttributesContainer = SWTFactory.createComposite(container, container.getFont(), 2, 1, GridData.FILL_HORIZONTAL);
        boolean isValue = fLogicalStructure.getValue() != null;
        if (!isValue) {
            // creates the attribute list if needed
            createAttributeListWidgets();
        }
        //$NON-NLS-1$
        fCodeGroup = SWTFactory.createGroup(container, "", 1, 1, GridData.FILL_BOTH);
        createCodeGroupWidgets(isValue);
        applyDialogFont(container);
        initializeData();
        return container;
    }

    /**
	 * Create the widgets it the code snippet editor group
	 * @param isValue if it is a snippet value
	 */
    private void createCodeGroupWidgets(boolean isValue) {
        if (isValue) {
            fCodeGroup.setText(DebugUIMessages.EditLogicalStructureDialog_9);
        } else {
            fCodeGroup.setText(DebugUIMessages.EditLogicalStructureDialog_7);
            Composite attributeNameContainer = SWTFactory.createComposite(fCodeGroup, fCodeGroup.getFont(), 2, 1, GridData.FILL_HORIZONTAL);
            ((GridLayout) attributeNameContainer.getLayout()).marginWidth = 0;
            SWTFactory.createLabel(attributeNameContainer, DebugUIMessages.EditLogicalStructureDialog_8, 1);
            fAttributeNameText = SWTFactory.createSingleText(attributeNameContainer, 1);
            fAttributeNameText.addListener(SWT.Modify, this);
            SWTFactory.createLabel(fCodeGroup, DebugUIMessages.EditLogicalStructureDialog_9, 1);
        }
        // snippet viewer
        fSnippetViewer = new JDISourceViewer(fCodeGroup, null, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.LEFT_TO_RIGHT);
        fSnippetViewer.setInput(this);
        JavaTextTools tools = JDIDebugUIPlugin.getDefault().getJavaTextTools();
        if (fSnippetDocument == null) {
            fSnippetDocument = new Document();
            fSnippetDocument.addDocumentListener(this);
        }
        tools.setupJavaDocumentPartitioner(fSnippetDocument, IJavaPartitions.JAVA_PARTITIONING);
        if (fViewerConfiguration == null) {
            fViewerConfiguration = new DisplayViewerConfiguration() {

                @Override
                public IContentAssistProcessor getContentAssistantProcessor() {
                    return new JavaDebugContentAssistProcessor(new DynamicTypeContext(EditLogicalStructureDialog.this));
                }
            };
        }
        fSnippetViewer.configure(fViewerConfiguration);
        fSnippetViewer.setEditable(true);
        fSnippetViewer.setDocument(fSnippetDocument);
        Control control = fSnippetViewer.getControl();
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.heightHint = convertHeightInCharsToPixels(isValue ? 20 : 10);
        gd.widthHint = convertWidthInCharsToPixels(80);
        control.setLayoutData(gd);
    }

    /**
	 * Create the widgets for the attribute list
	 */
    private void createAttributeListWidgets() {
        fAttributeListViewer = new TableViewer(fAttributesContainer, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
        Table table = (Table) fAttributeListViewer.getControl();
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false);
        gd.heightHint = convertHeightInCharsToPixels(5);
        gd.widthHint = convertWidthInCharsToPixels(10);
        table.setLayoutData(gd);
        table.setFont(fAttributesContainer.getFont());
        if (fAttributesContentProvider == null) {
            fAttributesContentProvider = new AttributesContentProvider(fLogicalStructure.getVariables());
        }
        fAttributeListViewer.setContentProvider(fAttributesContentProvider);
        fAttributeListViewer.setLabelProvider(new AttributesLabelProvider());
        fAttributeListViewer.setInput(this);
        fAttributeListViewer.addSelectionChangedListener(this);
        Composite attributeListButtonsCotnainer = SWTFactory.createComposite(fAttributesContainer, fAttributesContainer.getFont(), 1, 1, SWT.NONE);
        fAttributeAddButton = SWTFactory.createPushButton(attributeListButtonsCotnainer, DebugUIMessages.EditLogicalStructureDialog_10, DebugUIMessages.EditLogicalStructureDialog_27, null);
        fAttributeAddButton.addListener(SWT.Selection, this);
        fAttributeRemoveButton = SWTFactory.createPushButton(attributeListButtonsCotnainer, DebugUIMessages.EditLogicalStructureDialog_11, DebugUIMessages.EditLogicalStructureDialog_28, null);
        fAttributeRemoveButton.addListener(SWT.Selection, this);
        fAttributeUpButton = SWTFactory.createPushButton(attributeListButtonsCotnainer, DebugUIMessages.EditLogicalStructureDialog_12, DebugUIMessages.EditLogicalStructureDialog_29, null);
        fAttributeUpButton.addListener(SWT.Selection, this);
        fAttributeDownButton = SWTFactory.createPushButton(attributeListButtonsCotnainer, DebugUIMessages.EditLogicalStructureDialog_13, DebugUIMessages.EditLogicalStructureDialog_30, null);
        fAttributeDownButton.addListener(SWT.Selection, this);
    }

    private void initializeData() {
        fQualifiedTypeNameText.setText(fLogicalStructure.getQualifiedTypeName());
        fDescriptionText.setText(fLogicalStructure.getDescription());
        fSubTypeButton.setSelection(fLogicalStructure.isSubtypes());
        fValueTmp = fLogicalStructure.getValue();
        if (fValueTmp == null) {
            //$NON-NLS-1$
            fValueTmp = "";
            fVariablesButton.setSelection(true);
            setAttributesData(false);
        } else {
            fValueButton.setSelection(true);
            setAttributesData(true);
        }
        checkValues();
    }

    /* (non-Javadoc)
	 * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
	 */
    @Override
    public void handleEvent(Event event) {
        Widget source = event.widget;
        switch(event.type) {
            case SWT.Selection:
                if (source == fValueButton) {
                    toggleAttributesWidgets(fValueButton.getSelection());
                    checkValues();
                } else if (source == fBrowseTypeButton) {
                    selectType();
                } else if (source == fAttributeAddButton) {
                    addAttribute();
                } else if (source == fAttributeRemoveButton) {
                    removeAttribute();
                } else if (source == fAttributeUpButton) {
                    attributeUp();
                } else if (source == fAttributeDownButton) {
                    attributeDown();
                }
                break;
            case SWT.Modify:
                if (source == fAttributeNameText) {
                    saveNewAttributeName();
                    checkValues();
                } else if (source == fQualifiedTypeNameText) {
                    checkValues();
                    fTypeSearched = false;
                } else if (source == fDescriptionText) {
                    checkValues();
                }
                break;
        }
    }

    // code for add attribute button
    private void addAttribute() {
        String[] newAttribute = new String[] { DebugUIMessages.EditLogicalStructureDialog_14, // 
        DebugUIMessages.EditLogicalStructureDialog_15 };
        fAttributesContentProvider.add(newAttribute);
        fAttributeListViewer.refresh();
        fAttributeListViewer.setSelection(new StructuredSelection((Object) newAttribute));
    }

    // code for remove attribute button
    private void removeAttribute() {
        IStructuredSelection selection = (IStructuredSelection) fAttributeListViewer.getSelection();
        if (selection.size() > 0) {
            List<String[]> selectedElements = selection.toList();
            Object[] elements = fAttributesContentProvider.getElements();
            Object newSelectedElement = null;
            for (int i = 0; i < elements.length; i++) {
                if (!selectedElements.contains(elements[i])) {
                    newSelectedElement = elements[i];
                } else {
                    break;
                }
            }
            fAttributesContentProvider.remove(selectedElements);
            fAttributeListViewer.refresh();
            if (newSelectedElement == null) {
                Object[] newElements = fAttributesContentProvider.getElements();
                if (newElements.length > 0) {
                    fAttributeListViewer.setSelection(new StructuredSelection(newElements[0]));
                }
            } else {
                fAttributeListViewer.setSelection(new StructuredSelection(newSelectedElement));
            }
        }
    }

    // code for attribute up button
    private void attributeUp() {
        IStructuredSelection selection = (IStructuredSelection) fAttributeListViewer.getSelection();
        if (selection.size() > 0) {
            fAttributesContentProvider.up(selection.toList());
            fAttributeListViewer.refresh();
            fAttributeListViewer.setSelection(selection);
        }
    }

    // code for attribute down button
    private void attributeDown() {
        IStructuredSelection selection = (IStructuredSelection) fAttributeListViewer.getSelection();
        if (selection.size() > 0) {
            fAttributesContentProvider.down(selection.toList());
            fAttributeListViewer.refresh();
            fAttributeListViewer.setSelection(selection);
        }
    }

    // save the new attribute name typed by the user
    private void saveNewAttributeName() {
        if (fCurrentAttributeSelection.size() == 1) {
            String[] variable = (String[]) fCurrentAttributeSelection.getFirstElement();
            variable[0] = fAttributeNameText.getText();
            fAttributeListViewer.refresh(variable);
        }
    }

    /*
	 * Display or hide the widgets specific to a logical structure with
	 * variables.
	 */
    private void toggleAttributesWidgets(boolean isValue) {
        if (!isValue) {
            // recreate the attribute list
            fValueTmp = fSnippetDocument.get();
            createAttributeListWidgets();
        } else if (isValue) {
            // dispose the attribute list
            saveAttributeValue();
            Control[] children = fAttributesContainer.getChildren();
            for (int i = 0; i < children.length; i++) {
                children[i].dispose();
            }
        }
        // dispose and recreate the code snippet editor group
        Control[] children = fCodeGroup.getChildren();
        for (int i = 0; i < children.length; i++) {
            children[i].dispose();
        }
        fSnippetViewer.dispose();
        createCodeGroupWidgets(isValue);
        setAttributesData(isValue);
        fParentComposite.layout(true, true);
    }

    /**
	 * Set the data in the attributes and code widgets
	 * @param isValue if it is a snippet value
	 */
    private void setAttributesData(boolean isValue) {
        if (isValue) {
            fSnippetDocument.set(fValueTmp);
        } else {
            Object[] elements = fAttributesContentProvider.getElements(null);
            fCurrentAttributeSelection = new StructuredSelection();
            if (elements.length > 0) {
                IStructuredSelection newSelection = new StructuredSelection(elements[0]);
                fAttributeListViewer.setSelection(newSelection);
            } else {
                fAttributeListViewer.setSelection(fCurrentAttributeSelection);
            }
        }
    }

    // save the code to the current attribute.
    private void saveAttributeValue() {
        if (fCurrentAttributeSelection.size() == 1) {
            ((String[]) fCurrentAttributeSelection.getFirstElement())[1] = fSnippetDocument.get();
        }
    }

    /* (non-Javadoc)
	 * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
	 */
    @Override
    public void selectionChanged(SelectionChangedEvent event) {
        saveAttributeValue();
        fCurrentAttributeSelection = (IStructuredSelection) event.getSelection();
        boolean sizeone = fCurrentAttributeSelection.size() == 1;
        //update viewers
        fAttributeNameText.setEnabled(sizeone);
        fSnippetViewer.setEditable(sizeone);
        if (sizeone) {
            String[] variable = (String[]) fCurrentAttributeSelection.getFirstElement();
            fAttributeNameText.setText(variable[0]);
            fSnippetDocument.set(variable[1]);
            fAttributeNameText.setSelection(0, variable[0].length());
            fAttributeNameText.setFocus();
        } else {
            //$NON-NLS-1$
            fAttributeNameText.setText("");
            //$NON-NLS-1$
            fSnippetDocument.set("");
        }
        //update buttons
        fAttributeRemoveButton.setEnabled(fCurrentAttributeSelection.size() > 0);
        int index = fAttributeListViewer.getTable().getSelectionIndex();
        fAttributeUpButton.setEnabled(sizeone && (index != 0));
        fAttributeDownButton.setEnabled(sizeone && (index != fAttributeListViewer.getTable().getItemCount() - 1));
    }

    /**
	 * Check the values in the widgets.
	 */
    public void checkValues() {
        StatusInfo status = new StatusInfo();
        if (fQualifiedTypeNameText.getText().trim().length() == 0) {
            status.setError(DebugUIMessages.EditLogicalStructureDialog_16);
        } else if (fDescriptionText.getText().trim().length() == 0) {
            status.setError(DebugUIMessages.EditLogicalStructureDialog_17);
        } else if (fValueButton.getSelection() && fSnippetDocument.get().length() == 0) {
            status.setError(DebugUIMessages.EditLogicalStructureDialog_18);
        } else if (fVariablesButton.getSelection()) {
            Object[] elements = fAttributesContentProvider.getElements(null);
            boolean oneElementSelected = fCurrentAttributeSelection.size() == 1;
            if (elements.length == 0) {
                status.setError(DebugUIMessages.EditLogicalStructureDialog_19);
            } else if (oneElementSelected && fAttributeNameText.getText().trim().length() == 0) {
                status.setError(DebugUIMessages.EditLogicalStructureDialog_20);
            } else if (oneElementSelected && fSnippetDocument.get().trim().length() == 0) {
                status.setError(DebugUIMessages.EditLogicalStructureDialog_21);
            } else {
                for (int i = 0; i < elements.length; i++) {
                    String[] variable = (String[]) elements[i];
                    if (variable[0].trim().length() == 0) {
                        status.setError(DebugUIMessages.EditLogicalStructureDialog_22);
                        break;
                    }
                    if (variable[1].trim().length() == 0) {
                        if (!oneElementSelected || fCurrentAttributeSelection.getFirstElement() != variable) {
                            status.setError(NLS.bind(DebugUIMessages.EditLogicalStructureDialog_23, new String[] { variable[0] }));
                            break;
                        }
                    }
                }
            }
        }
        if (!status.isError()) {
            if (fType == null && fTypeSearched) {
                status.setWarning(DebugUIMessages.EditLogicalStructureDialog_24);
            }
        }
        updateStatus(status);
    }

    /**
	 * Open the 'select type' dialog, and set the user choice into the formatter.
	 */
    private void selectType() {
        Shell shell = getShell();
        SelectionDialog dialog = null;
        try {
            dialog = JavaUI.createTypeDialog(shell, PlatformUI.getWorkbench().getProgressService(), SearchEngine.createWorkspaceScope(), IJavaElementSearchConstants.CONSIDER_ALL_TYPES, false, fQualifiedTypeNameText.getText());
        } catch (JavaModelException jme) {
            String title = DebugUIMessages.DetailFormatterDialog_Select_type_6;
            String message = DebugUIMessages.DetailFormatterDialog_Could_not_open_type_selection_dialog_for_detail_formatters_7;
            ExceptionHandler.handle(jme, title, message);
            return;
        }
        dialog.setTitle(DebugUIMessages.DetailFormatterDialog_Select_type_8);
        dialog.setMessage(DebugUIMessages.DetailFormatterDialog_Select_a_type_to_format_when_displaying_its_detail_9);
        if (dialog.open() == IDialogConstants.CANCEL_ID) {
            return;
        }
        Object[] types = dialog.getResult();
        if (types != null && types.length > 0) {
            fType = (IType) types[0];
            fQualifiedTypeNameText.setText(fType.getFullyQualifiedName());
            fTypeSearched = true;
        }
    }

    /* (non-Javadoc)
	 * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
	 */
    @Override
    public void documentAboutToBeChanged(DocumentEvent event) {
    // nothing to do
    }

    /* (non-Javadoc)
	 * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
	 */
    @Override
    public void documentChanged(DocumentEvent event) {
        checkValues();
    }

    /* (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.Dialog#okPressed()
	 */
    @Override
    protected void okPressed() {
        // save the new data in the logical structure
        fLogicalStructure.setType(fQualifiedTypeNameText.getText().trim());
        fLogicalStructure.setDescription(fDescriptionText.getText().trim());
        fLogicalStructure.setSubtypes(fSubTypeButton.getSelection());
        if (fValueButton.getSelection()) {
            fLogicalStructure.setValue(fSnippetDocument.get());
        } else {
            saveAttributeValue();
            fLogicalStructure.setValue(null);
        }
        if (fAttributesContentProvider != null) {
            fLogicalStructure.setVariables(fAttributesContentProvider.getElements());
        }
        super.okPressed();
    }

    /**
	 * Use the Java search engine to find the type which corresponds
	 * to the given name.
	 */
    private void findCorrespondingType() {
        if (fTypeSearched) {
            return;
        }
        fType = null;
        fTypeSearched = true;
        final String pattern = fQualifiedTypeNameText.getText().trim().replace('$', '.');
        if (//$NON-NLS-1$
        pattern == null || "".equals(pattern)) {
            return;
        }
        final IProgressMonitor monitor = new NullProgressMonitor();
        final SearchRequestor collector = new SearchRequestor() {

            private boolean fFirst = true;

            @Override
            public void endReporting() {
                checkValues();
            }

            @Override
            public void acceptSearchMatch(SearchMatch match) throws CoreException {
                Object enclosingElement = match.getElement();
                if (!fFirst) {
                    return;
                }
                fFirst = false;
                if (enclosingElement instanceof IType) {
                    fType = (IType) enclosingElement;
                }
                // stop after we find one
                monitor.setCanceled(true);
            }
        };
        SearchEngine engine = new SearchEngine(JavaCore.getWorkingCopies(null));
        SearchPattern searchPattern = SearchPattern.createPattern(pattern, IJavaSearchConstants.TYPE, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
        IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
        SearchParticipant[] participants = new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
        try {
            engine.search(searchPattern, participants, scope, collector, monitor);
        } catch (CoreException e) {
            JDIDebugUIPlugin.log(e);
        } catch (OperationCanceledException e) {
        }
    }

    /**
	 * Return the type object which corresponds to the given name.
	 * @return the {@link IType}
	 */
    @Override
    public IType getType() {
        if (!fTypeSearched) {
            findCorrespondingType();
        }
        return fType;
    }

    /* (non-Javadoc)
	 * @see org.eclipse.jface.dialogs.Dialog#close()
	 */
    @Override
    public boolean close() {
        IWorkbench workbench = PlatformUI.getWorkbench();
        IHandlerService handlerService = workbench.getAdapter(IHandlerService.class);
        handlerService.deactivateHandler(fHandlerActivation);
        fSnippetViewer.dispose();
        return super.close();
    }
}
