content: /*******************************************************************************
   * Copyright (c) 2000, 2009 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.wst.jsdt.internal.ui.refactoring;
  
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Set;
  
  import org.eclipse.jface.dialogs.Dialog;
  import org.eclipse.jface.dialogs.IDialogSettings;
  import org.eclipse.jface.dialogs.IMessageProvider;
  import org.eclipse.jface.viewers.ISelectionChangedListener;
  import org.eclipse.jface.viewers.IStructuredSelection;
  import org.eclipse.jface.viewers.ITreeContentProvider;
  import org.eclipse.jface.viewers.SelectionChangedEvent;
  import org.eclipse.jface.viewers.TreeViewer;
  import org.eclipse.jface.viewers.Viewer;
  import org.eclipse.jface.viewers.ViewerComparator;
  import org.eclipse.jface.wizard.IWizardPage;
  import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
  import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.events.SelectionAdapter;
  import org.eclipse.swt.events.SelectionEvent;
  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.swt.widgets.Tree;
  import org.eclipse.swt.widgets.TreeItem;
  import org.eclipse.ui.PlatformUI;
  import org.eclipse.wst.jsdt.core.IType;
  import org.eclipse.wst.jsdt.core.ITypeHierarchy;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.UseSuperTypeProcessor;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.UseSuperTypeRefactoring;
  import org.eclipse.wst.jsdt.internal.corext.util.Messages;
  import org.eclipse.wst.jsdt.internal.corext.util.SuperTypeHierarchyCache;
  import org.eclipse.wst.jsdt.internal.ui.IJavaHelpContextIds;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.ui.JavaScriptElementLabelProvider;
  import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels;
  
  public class UseSupertypeWizard extends RefactoringWizard{
  
  	/* package */ static final String DIALOG_SETTING_SECTION= "UseSupertypeWizard"; //$NON-NLS-1$
  	
  	public UseSupertypeWizard(UseSuperTypeRefactoring ref) {
  		super(ref, DIALOG_BASED_USER_INTERFACE);
  		setDefaultPageTitle(RefactoringMessages.UseSupertypeWizard_Use_Super_Type_Where_Possible); 
  	}
  
  	protected void addUserInputPages(){
  		addPage(new UseSupertypeInputPage());
  	}
  
  	private static class UseSupertypeInputPage extends UserInputWizardPage{
  
  		private class UseSupertypeContentProvider implements ITreeContentProvider {
  
  			private ITypeHierarchy fHierarchy;
  			
  			public Object[] getChildren(Object element) {
  				if (element instanceof ITypeHierarchy)
  					return getElements(element);
  				return getDirectSuperTypes((IType)element).toArray();
  			}
  
  			public Set/*<IType>*/ getDirectSuperTypes(IType type){
  				Set/*<IType>*/ result= new HashSet();
  				final IType superclass= fHierarchy.getSuperclass(type);
  				if (superclass != null) {
  					result.add(superclass);
  				}	
  				return result;
  			}	
  
  			public Object[] getElements(Object element) {
  				if (element instanceof ITypeHierarchy)
  					return getChildren(((ITypeHierarchy) element).getType());
  				return new Object[0];
  			}
  
  			public boolean hasChildren(Object element) {
  				return getChildren(element).length > 0;
  			}
  
  			public Object getParent(Object element) {
  				return null;
  			}
  
  			public void dispose() {
  				// Do nothing
  			}
  
  			public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
  				if (newInput instanceof ITypeHierarchy)
  					fHierarchy= (ITypeHierarchy) newInput;
  				else
  					fHierarchy= null;
  			}
  		}
  
  		private static final String REWRITE_INSTANCEOF= "rewriteInstanceOf";  //$NON-NLS-1$
  		public static final String PAGE_NAME= "UseSupertypeInputPage";//$NON-NLS-1$
  		private TreeViewer fTreeViewer; 
  		private final Map fFileCount;  //IType -> Integer
  		private final static String MESSAGE= RefactoringMessages.UseSupertypeInputPage_Select_supertype; 
  		private JavaScriptElementLabelProvider fLabelProvider;
  		private IDialogSettings fSettings;
  		
  		public UseSupertypeInputPage() {
  			super(PAGE_NAME);
  			fFileCount= new HashMap(2);
  			setMessage(MESSAGE);
  		}
  
  		private void loadSettings() {
  			fSettings= getDialogSettings().getSection(UseSupertypeWizard.DIALOG_SETTING_SECTION);
  			if (fSettings == null) {
  				fSettings= getDialogSettings().addNewSection(UseSupertypeWizard.DIALOG_SETTING_SECTION);
  				fSettings.put(REWRITE_INSTANCEOF, false);
  			}
  			getUseSupertypeProcessor().setInstanceOf(fSettings.getBoolean(REWRITE_INSTANCEOF));
  		}
  
  		private UseSuperTypeProcessor getUseSupertypeProcessor() {
  			return getUseSupertypeRefactoring().getUseSuperTypeProcessor();
  		}
  
  		private UseSuperTypeRefactoring getUseSupertypeRefactoring() {
  			return ((UseSuperTypeRefactoring)getRefactoring());
  		}	
  
  		public void createControl(Composite parent) {
  			initializeDialogUnits(parent);
  			loadSettings();
  			Composite composite= new Composite(parent, SWT.NONE);
  			setControl(composite);
  			composite.setLayout(new GridLayout());
  
  			Label label= new Label(composite, SWT.NONE);
  			label.setText(Messages.format(
  					RefactoringMessages.UseSupertypeInputPage_Select_supertype_to_use, 
  					JavaScriptElementLabels.getElementLabel(getUseSupertypeProcessor().getSubType(), JavaScriptElementLabels.T_FULLY_QUALIFIED)));
  			label.setLayoutData(new GridData());
  		
  			addTreeViewer(composite);
  
  			final Button checkbox= new Button(composite, SWT.CHECK);
  			checkbox.setText(RefactoringMessages.UseSupertypeInputPage_Use_in_instanceof); 
  			checkbox.setLayoutData(new GridData());
  			checkbox.setSelection(getUseSupertypeProcessor().isInstanceOf());
  			checkbox.addSelectionListener(new SelectionAdapter(){
  				public void widgetSelected(SelectionEvent e) {
  					getUseSupertypeProcessor().setInstanceOf(checkbox.getSelection());
  					fSettings.put(REWRITE_INSTANCEOF, checkbox.getSelection());
  					setMessage(MESSAGE);
  					setPageComplete(true);
  					fFileCount.clear();
  					fTreeViewer.refresh();
  				}
  			});
  
  			Dialog.applyDialogFont(composite);
  			PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IJavaHelpContextIds.USE_SUPERTYPE_WIZARD_PAGE);
  		}
  
  		private void addTreeViewer(Composite composite) {
  			fTreeViewer= new TreeViewer(composite, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
  			final Tree tree= fTreeViewer.getTree();
  			final GridData data= new GridData(GridData.FILL_BOTH);
  			data.heightHint= convertHeightInCharsToPixels(12);
  			tree.setLayoutData(data);
  			fLabelProvider= new UseSupertypeLabelProvider(fFileCount);
  			fTreeViewer.setLabelProvider(fLabelProvider);
  			fTreeViewer.setContentProvider(new UseSupertypeContentProvider());
  			fTreeViewer.setComparator(new ViewerComparator() {
  							
  				public boolean isSorterProperty(Object element, String property) {
  					return true;
  				}
  			
  				public int compare(Viewer viewer, Object first, Object second) {
  					final IType type1= (IType)first;
  					final IType type2= (IType)second;
  					
  					return getComparator().compare(type1.getElementName(), type2.getElementName());
  				}
  			});
  			fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener(){
  				public void selectionChanged(SelectionChangedEvent event) {
  					IStructuredSelection ss= (IStructuredSelection)event.getSelection();
  					if (Integer.valueOf(0).equals(fFileCount.get(ss.getFirstElement()))){
  						setMessage(RefactoringMessages.UseSupertypeInputPage_No_updates, IMessageProvider.INFORMATION); 
  						setPageComplete(false);
  					} else {
  						setMessage(MESSAGE);
  						setPageComplete(true);
  					}
  					fTreeViewer.refresh();
  				}
  			});
  			try {
  				fTreeViewer.setInput(SuperTypeHierarchyCache.getTypeHierarchy(getUseSupertypeProcessor().getSubType()));
  			} catch (JavaScriptModelException exception) {
  				JavaScriptPlugin.log(exception);
  			}
  			fTreeViewer.expandAll();
  			final TreeItem[] items= tree.getItems();
  			if (items.length > 0)
  				tree.setSelection(new TreeItem[] {items[0]});
  		}
  
  		public IWizardPage getNextPage() {
  			initializeRefactoring();
  			IWizardPage nextPage= super.getNextPage();
  			updateUpdateLabels();
  			return nextPage;
  		}
  
  		private void updateUpdateLabels() {
  			IType selectedType= getSelectedSupertype();
  			final int count= getUseSupertypeProcessor().getChanges();
  			fFileCount.put(selectedType, Integer.valueOf(count));
  			if (count == 0) {
  				setMessage(RefactoringMessages.UseSupertypeInputPage_No_updates, IMessageProvider.INFORMATION); 
  				setPageComplete(false);
  			}
  			fTreeViewer.refresh();
  			if (noSupertypeCanBeUsed()){
  				setMessage(RefactoringMessages.UseSupertypeWizard_10, IMessageProvider.INFORMATION); 
  				setPageComplete(false);	
  			}
  		}
  
  		private boolean noSupertypeCanBeUsed() {
  			return fTreeViewer.getTree().getItemCount() == countFilesWithValue(0);
  		}
  
  		private int countFilesWithValue(int i) {
  			int count= 0;
  			for (Iterator iter= fFileCount.keySet().iterator(); iter.hasNext();) {
  				if (((Integer)fFileCount.get(iter.next())).intValue() == i)
  					count++;
  			}
  			return count;
  		}
  
  		private IType getSelectedSupertype() {
  			IStructuredSelection ss= (IStructuredSelection)fTreeViewer.getSelection();
  			return (IType)ss.getFirstElement();
  		}
  
  		public boolean performFinish(){
  			initializeRefactoring();
  			boolean superFinish= super.performFinish();
  			if (! superFinish)
  				return false;
  			final int count= getUseSupertypeProcessor().getChanges();
  			if (count == 0) {
  				updateUpdateLabels();
  				return false;
  			}
  			return superFinish;
  		}
  
  		private void initializeRefactoring() {
  			IStructuredSelection ss= (IStructuredSelection)fTreeViewer.getSelection();
  			getUseSupertypeProcessor().setSuperType((IType)ss.getFirstElement());
  		}
  
  		public void dispose() {
  			fTreeViewer= null;
  			fFileCount.clear();
  			fLabelProvider= null;
  			super.dispose();
  		}
  	
  		private static class UseSupertypeLabelProvider extends JavaScriptElementLabelProvider{
  			private final Map fFileCount;
  			private UseSupertypeLabelProvider(Map fileCount){
  				fFileCount= fileCount;
  			}
  			public String getText(Object element) {
  				String superText= super.getText(element);
  				if  (! fFileCount.containsKey(element))
  					return superText;
  				int count= ((Integer)fFileCount.get(element)).intValue();
  				if (count == 0){
  					String[] keys= {superText};
  					return Messages.format(RefactoringMessages.UseSupertypeInputPage_no_possible_updates, keys); 
  				} else if (count == 1){
  					String [] keys= {superText};
  					return Messages.format(RefactoringMessages.UseSupertypeInputPage_updates_possible_in_file, keys); 
  				}	else {
  					String[] keys= {superText, String.valueOf(count)};
  					return Messages.format(RefactoringMessages.UseSupertypeInputPage_updates_possible_in_files, keys); 
  				}	
  			}
  		}
  
  		public void setVisible(boolean visible) {
  			super.setVisible(visible);
  			if (visible && fTreeViewer != null)
  				fTreeViewer.getTree().setFocus();
  		}
  	}
  }
  