content: /*******************************************************************************
   * Copyright (c) 2000, 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 Corporation - initial API and implementation
   *******************************************************************************/
  package org.eclipse.wst.jsdt.internal.ui.fix;
  
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.UnsupportedEncodingException;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Hashtable;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  
  import org.eclipse.core.resources.ProjectScope;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.preferences.IEclipsePreferences;
  import org.eclipse.core.runtime.preferences.InstanceScope;
  import org.eclipse.jface.dialogs.ControlEnableState;
  import org.eclipse.jface.dialogs.Dialog;
  import org.eclipse.jface.viewers.ColumnLayoutData;
  import org.eclipse.jface.viewers.ColumnWeightData;
  import org.eclipse.jface.viewers.ITableLabelProvider;
  import org.eclipse.jface.viewers.LabelProvider;
  import org.eclipse.jface.viewers.StructuredSelection;
  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.graphics.Image;
  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.Link;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.swt.widgets.Table;
  import org.eclipse.ui.dialogs.PreferencesUtil;
  import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
  import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  import org.eclipse.wst.jsdt.internal.corext.fix.CleanUpConstants;
  import org.eclipse.wst.jsdt.internal.corext.fix.CleanUpPreferenceUtil;
  import org.eclipse.wst.jsdt.internal.corext.fix.CleanUpRefactoring;
  import org.eclipse.wst.jsdt.internal.corext.util.Messages;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.JavaPluginImages;
  import org.eclipse.wst.jsdt.internal.ui.preferences.BulletListBlock;
  import org.eclipse.wst.jsdt.internal.ui.preferences.CleanUpPreferencePage;
  import org.eclipse.wst.jsdt.internal.ui.preferences.cleanup.CleanUpProfileVersioner;
  import org.eclipse.wst.jsdt.internal.ui.preferences.cleanup.CleanUpTabPage;
  import org.eclipse.wst.jsdt.internal.ui.preferences.cleanup.CodeFormatingTabPage;
  import org.eclipse.wst.jsdt.internal.ui.preferences.cleanup.CodeStyleTabPage;
  import org.eclipse.wst.jsdt.internal.ui.preferences.cleanup.UnnecessaryCodeTabPage;
  import org.eclipse.wst.jsdt.internal.ui.preferences.formatter.ProfileManager;
  import org.eclipse.wst.jsdt.internal.ui.preferences.formatter.ProfileStore;
  import org.eclipse.wst.jsdt.internal.ui.preferences.formatter.ModifyDialogTabPage.IModificationListener;
  import org.eclipse.wst.jsdt.internal.ui.preferences.formatter.ProfileManager.CustomProfile;
  import org.eclipse.wst.jsdt.internal.ui.preferences.formatter.ProfileManager.Profile;
  import org.eclipse.wst.jsdt.internal.ui.util.SWTUtil;
  import org.eclipse.wst.jsdt.internal.ui.wizards.dialogfields.DialogField;
  import org.eclipse.wst.jsdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
  import org.eclipse.wst.jsdt.internal.ui.wizards.dialogfields.IListAdapter;
  import org.eclipse.wst.jsdt.internal.ui.wizards.dialogfields.ListDialogField;
  import org.eclipse.wst.jsdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField;
  import org.eclipse.wst.jsdt.ui.JavaScriptUI;
  import org.xml.sax.InputSource;
  
  public class CleanUpRefactoringWizard extends RefactoringWizard {
  	
  	private static final String USE_CUSTOM_PROFILE_KEY= "org.eclipse.wst.jsdt.ui.cleanup.use_dialog_profile"; //$NON-NLS-1$
  	private static final String CUSTOM_PROFILE_KEY= "org.eclipse.wst.jsdt.ui.cleanup.custom_profile"; //$NON-NLS-1$
  	
  	private static class ProjectProfileLableProvider extends LabelProvider implements ITableLabelProvider {
  
  		private Hashtable fProfileIdsTable;
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public Image getColumnImage(Object element, int columnIndex) {
  			return null;
  		}
  
  		/**
  		 * {@inheritDoc}
  		 */
  		public String getColumnText(Object element, int columnIndex) {
  			if (columnIndex == 0) {
  				return ((IJavaScriptProject)element).getProject().getName();
  			} else if (columnIndex == 1) {
  				
  				if (fProfileIdsTable == null)
  		    		fProfileIdsTable= loadProfiles();
  				
  				InstanceScope instanceScope= new InstanceScope();
  	    		IEclipsePreferences instancePreferences= instanceScope.getNode(JavaScriptUI.ID_PLUGIN);
  	
  	    		final String workbenchProfileId;
  	    		if (instancePreferences.get(CleanUpConstants.CLEANUP_PROFILE, null) != null) {
  	    			workbenchProfileId= instancePreferences.get(CleanUpConstants.CLEANUP_PROFILE, null);
  	    		} else {
  	    			workbenchProfileId= CleanUpConstants.DEFAULT_PROFILE;
  	    		}
  	    		
  				return getProjectProfileName((IJavaScriptProject)element, fProfileIdsTable, workbenchProfileId);
  			}
  			return null;
  		}
  		
  		private Hashtable loadProfiles() {
      		List list= CleanUpPreferenceUtil.loadProfiles(new InstanceScope());
      		
      		Hashtable profileIdsTable= new Hashtable();
      		for (Iterator iterator= list.iterator(); iterator.hasNext();) {
  	            Profile profile= (Profile)iterator.next();
  	            profileIdsTable.put(profile.getID(), profile);
              }
  	     
      		return profileIdsTable;
          }
  
  		private String getProjectProfileName(final IJavaScriptProject project, Hashtable profileIdsTable, String workbenchProfileId) {
  			ProjectScope projectScope= new ProjectScope(project.getProject());
  	        IEclipsePreferences node= projectScope.getNode(JavaScriptUI.ID_PLUGIN);
  	        String id= node.get(CleanUpConstants.CLEANUP_PROFILE, null);
  			if (id == null) {
  	        	Profile profile= (Profile)profileIdsTable.get(workbenchProfileId);
  		        if (profile != null) {
  		        	return profile.getName();
  		        } else {
  		        	return MultiFixMessages.CleanUpRefactoringWizard_unknownProfile_Name;
  		        }
  	        } else {
  		        Profile profile= (Profile)profileIdsTable.get(id);
  		        if (profile != null) {
  		        	return profile.getName();
  		        } else {
  		        	return Messages.format(MultiFixMessages.CleanUpRefactoringWizard_UnmanagedProfileWithName_Name, id.substring(ProfileManager.ID_PREFIX.length()));
  		        }
  	        }
          }
  
  		public void reset() {
  			fProfileIdsTable= null;
          }
  	}
  	
  	private static class CleanUpConfigurationPage extends UserInputWizardPage implements IModificationListener {
  
  		private static final class ProfileTableAdapter implements IListAdapter {
  	        private final ProjectProfileLableProvider fProvider;
  			private final Shell fShell;
  
  	        private ProfileTableAdapter(ProjectProfileLableProvider provider, Shell shell) {
  		        fProvider= provider;
  				fShell= shell;
  	        }
  
  	        public void customButtonPressed(ListDialogField field, int index) {
  	        	openPropertyDialog(field);
  	        }
  
  	        public void doubleClicked(ListDialogField field) {
  				openPropertyDialog(field);
  	        }
  	        
  	        private void openPropertyDialog(ListDialogField field) {
  	            IJavaScriptProject project= (IJavaScriptProject)field.getSelectedElements().get(0);
  	        	PreferencesUtil.createPropertyDialogOn(fShell, project, CleanUpPreferencePage.PROP_ID, null, null).open();
  	        	List selectedElements= field.getSelectedElements();
  	        	fProvider.reset();
  	        	field.refresh();
  	        	field.selectElements(new StructuredSelection(selectedElements));
              }
  
  	        public void selectionChanged(ListDialogField field) {
  	        	if (field.getSelectedElements().size() != 1) {
  	        		field.enableButton(0, false);
  	        	} else {
  	        		field.enableButton(0, true);
  	        	}
  	        }
          }
  
  		private static final String ENCODING= "UTF-8"; //$NON-NLS-1$
  
  		private final CleanUpRefactoring fCleanUpRefactoring;
  		private Map fCustomSettings;
  		private SelectionButtonDialogField fUseCustomField;
  		
  		private ControlEnableState fEnableState;
  
  		public CleanUpConfigurationPage(CleanUpRefactoring refactoring) {
  			super(MultiFixMessages.CleanUpRefactoringWizard_CleanUpConfigurationPage_title);
  			fCleanUpRefactoring= refactoring;
  			IJavaScriptUnit[] cus= fCleanUpRefactoring.getCompilationUnits();
  			IJavaScriptProject[] projects= fCleanUpRefactoring.getProjects();
  			if (cus.length == 1) {
  				setMessage(MultiFixMessages.CleanUpRefactoringWizard_CleaningUp11_Title);
  			} else if (projects.length == 1) {
  				setMessage(Messages.format(MultiFixMessages.CleanUpRefactoringWizard_CleaningUpN1_Title, Integer.valueOf(cus.length)));
  			} else {
  				setMessage(Messages.format(MultiFixMessages.CleanUpRefactoringWizard_CleaningUpNN_Title, new Object[] {Integer.valueOf(cus.length), Integer.valueOf(projects.length)}));
  			}
          }
  
  		/**
           * {@inheritDoc}
           */
          public void createControl(Composite parent) {
          	boolean isCustom= getDialogSettings().getBoolean(USE_CUSTOM_PROFILE_KEY);
          	
          	final Composite composite= new Composite(parent, SWT.NONE);
  			composite.setLayout(new GridLayout(2, false));
  			composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
  			composite.setFont(parent.getFont());
  			
  			SelectionButtonDialogField useProfile= new SelectionButtonDialogField(SWT.RADIO);
  			useProfile.setLabelText(MultiFixMessages.CleanUpRefactoringWizard_use_configured_radio);
  			useProfile.setSelection(!isCustom);
  			useProfile.doFillIntoGrid(composite, 2);
  			
  			ProjectProfileLableProvider tableLabelProvider= new ProjectProfileLableProvider();
  			IListAdapter listAdapter= new ProfileTableAdapter(tableLabelProvider, getShell());
  			String[] buttons= new String[] {
  				MultiFixMessages.CleanUpRefactoringWizard_Configure_Button
  			};
  			final ListDialogField settingsField= new ListDialogField(listAdapter, buttons, tableLabelProvider);
  			
  			String[] headerNames= new String[] {
  					MultiFixMessages.CleanUpRefactoringWizard_Project_TableHeader, 
  					MultiFixMessages.CleanUpRefactoringWizard_Profile_TableHeader
  			};
  			ColumnLayoutData[] columns = new ColumnLayoutData[] {
  					new ColumnWeightData(1, 100, true),
  					new ColumnWeightData(2, 20, true)
  			};
  			settingsField.setTableColumns(new ListDialogField.ColumnsDescription(columns , headerNames, true));
  			settingsField.setViewerComparator(new ViewerComparator());
  			
  			settingsField.doFillIntoGrid(composite, 3);
  			
  			Table table= settingsField.getTableViewer().getTable();			
  			GridData data= (GridData)settingsField.getListControl(null).getLayoutData();
  			data.horizontalIndent= 15;
  			data.grabExcessVerticalSpace= false;
  			data.heightHint= SWTUtil.getTableHeightHint(table, Math.min(5, fCleanUpRefactoring.getProjects().length + 1));
  			data.grabExcessHorizontalSpace= true;
  			data.verticalAlignment= GridData.BEGINNING;
  			
  			data= (GridData)settingsField.getButtonBox(null).getLayoutData();
  			data.grabExcessVerticalSpace= false;
  			data.verticalAlignment= GridData.BEGINNING;
  
  			data= (GridData)settingsField.getLabelControl(null).getLayoutData();
  			data.exclude= true;
  						
  			settingsField.setElements(Arrays.asList(fCleanUpRefactoring.getProjects()));
  			settingsField.selectFirstElement();
  			
  			fUseCustomField= new SelectionButtonDialogField(SWT.RADIO);
  			fUseCustomField.setLabelText(MultiFixMessages.CleanUpRefactoringWizard_use_custom_radio);
  			fUseCustomField.setSelection(isCustom);
  			fUseCustomField.doFillIntoGrid(composite, 2);
  			
  			String settings= getDialogSettings().get(CUSTOM_PROFILE_KEY);
  			if (settings == null) {
  				fCustomSettings= CleanUpConstants.getEclipseDefaultSettings();
  			} else {
  				try {
  	                fCustomSettings= decodeSettings(settings);
                  } catch (CoreException e) {
  	                JavaScriptPlugin.log(e);
  	                fCustomSettings= CleanUpConstants.getEclipseDefaultSettings();
                  }
  			}
  			
  			final BulletListBlock bulletListBlock= new BulletListBlock();
  			Control bulletList= bulletListBlock.createControl(composite);
  			GridData layoutData= (GridData)bulletList.getLayoutData();
  			(layoutData).horizontalIndent= 15;
  			layoutData.grabExcessVerticalSpace= true;
  			
  			final Button configure= new Button(composite, SWT.NONE);
  			configure.setText(MultiFixMessages.CleanUpRefactoringWizard_ConfigureCustomProfile_button);
  			
  			data= new GridData(SWT.TOP, SWT.LEAD, false, false);
  			data.widthHint= SWTUtil.getButtonWidthHint(configure);
  			configure.setLayoutData(data);
  			
  			showCustomSettings(bulletListBlock);
  			configure.addSelectionListener(new SelectionAdapter() {
  				/**
  				 * {@inheritDoc}
  				 */
  				public void widgetSelected(SelectionEvent e) {
  					CleanUpSaveParticipantConfigurationModifyDialog dialog= new CleanUpSaveParticipantConfigurationModifyDialog(getShell(), fCustomSettings, MultiFixMessages.CleanUpRefactoringWizard_CustomCleanUpsDialog_title) {
  						protected CleanUpTabPage[] createTabPages(Map workingValues) {
  							CleanUpTabPage[] result= new CleanUpTabPage[3];
  							result[0]= new CodeStyleTabPage(this, workingValues, false);
  //							result[1]= new MemberAccessesTabPage(this, workingValues, false);
  							result[1]= new UnnecessaryCodeTabPage(this, workingValues, false);
  //							result[3]= new MissingCodeTabPage(this, workingValues, false);
  							result[2]= new CodeFormatingTabPage(this, workingValues, false);
  							
  							addTabPage(MultiFixMessages.CleanUpRefactoringWizard_code_style_tab, result[0]);
  //							addTabPage(MultiFixMessages.CleanUpRefactoringWizard_member_accesses_tab, result[1]);
  							addTabPage(MultiFixMessages.CleanUpRefactoringWizard_unnecessary_code_tab, result[1]);
  //							addTabPage(MultiFixMessages.CleanUpRefactoringWizard_missing_code_tab, result[3]);
  							addTabPage(MultiFixMessages.CleanUpRefactoringWizard_code_organizing_tab, result[2]);
  							
  							return result;
  						}
  					};
  					dialog.open();
  					showCustomSettings(bulletListBlock);
  				}
  			});
  			
  			updateEnableState(isCustom, settingsField, configure, bulletListBlock);
  			
  			fUseCustomField.setDialogFieldListener(new IDialogFieldListener() {
  				public void dialogFieldChanged(DialogField field) {
  					updateEnableState(fUseCustomField.isSelected(), settingsField, configure, bulletListBlock);
                  }				
  			});
  			
  			Link preferencePageLink= new Link(composite, SWT.WRAP);
  			preferencePageLink.setText(MultiFixMessages.CleanUpRefactoringWizard_HideWizard_Link);
  			preferencePageLink.setFont(parent.getFont());
  			GridData gridData= new GridData(SWT.FILL, SWT.FILL, true, false);
  			gridData.widthHint= convertWidthInCharsToPixels(300);
  			gridData.horizontalSpan= 2;
  			preferencePageLink.setLayoutData(gridData);
  			preferencePageLink.addSelectionListener(new SelectionAdapter() {
  				/**
  				 * {@inheritDoc}
  				 */
  				public void widgetSelected(SelectionEvent e) {
  					PreferencesUtil.createPreferenceDialogOn(composite.getShell(), CleanUpPreferencePage.PREF_ID, null, null).open();
  				}
  			});
  			
  			setControl(composite);
  			
  			Dialog.applyDialogFont(composite);
          }
  
  		private void updateEnableState(boolean isCustom, final ListDialogField settingsField, Button configureCustom, BulletListBlock bulletListBlock) {
  			settingsField.getListControl(null).setEnabled(!isCustom);
  			if (isCustom) {				
  				fEnableState= ControlEnableState.disable(settingsField.getButtonBox(null));
  			} else if (fEnableState != null) {
  				fEnableState.restore();
  				fEnableState= null;
  			}
  			bulletListBlock.setEnabled(isCustom);
  			configureCustom.setEnabled(isCustom);
  		}
          
          private void showCustomSettings(BulletListBlock bulletListBlock) {
  			StringBuffer buf= new StringBuffer();
  			
  			final ICleanUp[] cleanUps= CleanUpRefactoring.createCleanUps(fCustomSettings);
  	    	for (int i= 0; i < cleanUps.length; i++) {
  		        String[] descriptions= cleanUps[i].getDescriptions();
  		        if (descriptions != null) {
  	    	        for (int j= 0; j < descriptions.length; j++) {
  	    	        	if (buf.length() > 0) {
  	    	        		buf.append('\n');	    	        		
  	    	        	}
  	    	            buf.append(descriptions[j]);
  	                }
  		        }
  	        }
  	    	bulletListBlock.setText(buf.toString());
          }
  		
          protected boolean performFinish() {
  			initializeRefactoring();
  			storeSettings();
  			return super.performFinish();
  		}
  
  		public IWizardPage getNextPage() {
  			initializeRefactoring();
  			storeSettings();
  			return super.getNextPage();
  		}
  		
  		private void storeSettings() {
  			getDialogSettings().put(USE_CUSTOM_PROFILE_KEY, fUseCustomField.isSelected());
  			try {
  	            getDialogSettings().put(CUSTOM_PROFILE_KEY, encodeSettings(fCustomSettings));
              } catch (CoreException e) {
  	            JavaScriptPlugin.log(e);
              }
          }
  
  		private void initializeRefactoring() {
  			ICleanUp[] cleanups;
  			if (fUseCustomField.isSelected()) {
  				cleanups= CleanUpRefactoring.createCleanUps(fCustomSettings);
  			} else {
  				cleanups= CleanUpRefactoring.createCleanUps();
  			}
  
  			CleanUpRefactoring refactoring= (CleanUpRefactoring)getRefactoring();
  			refactoring.clearCleanUps();
  			for (int i= 0; i < cleanups.length; i++) {
  	            refactoring.addCleanUp(cleanups[i]);
              }
          }
  		
  		public String encodeSettings(Map settings) throws CoreException {
  			ByteArrayOutputStream stream= new ByteArrayOutputStream(2000);
  			try {
  				CleanUpProfileVersioner versioner= new CleanUpProfileVersioner();
  				CustomProfile profile= new ProfileManager.CustomProfile("custom", settings, versioner.getCurrentVersion(), versioner.getProfileKind()); //$NON-NLS-1$
  				ArrayList profiles= new ArrayList();
  				profiles.add(profile);
  				ProfileStore.writeProfilesToStream(profiles, stream, ENCODING, versioner);
  				try {
  					return stream.toString(ENCODING);
  				} catch (UnsupportedEncodingException e) {
  					return stream.toString(); 
  				}
  			} finally {
  				try { stream.close(); } catch (IOException e) { /* ignore */ }
  			}
  		}
  		
  		public Map decodeSettings(String settings) throws CoreException {
  			byte[] bytes;
  			try {
  				bytes= settings.getBytes(ENCODING);
  			} catch (UnsupportedEncodingException e) {
  				bytes= settings.getBytes();
  			}
  			InputStream is= new ByteArrayInputStream(bytes);
  			try {
  				List res= ProfileStore.readProfilesFromStream(new InputSource(is));
  				if (res == null || res.size() == 0)
  					return CleanUpConstants.getEclipseDefaultSettings();
  				
  				CustomProfile profile= (CustomProfile)res.get(0);
  				new CleanUpProfileVersioner().update(profile);
  				return profile.getSettings();
  			} finally {
  				try { is.close(); } catch (IOException e) { /* ignore */ }
  			}
  		}
  
  		/**
           * {@inheritDoc}
           */
          public void updateStatus(IStatus status) {}
  
  		/**
           * {@inheritDoc}
           */
          public void valuesModified() {}
  	}
  	
  	public CleanUpRefactoringWizard(CleanUpRefactoring refactoring, int flags) {
  		super(refactoring, flags);
  		setDefaultPageTitle(MultiFixMessages.CleanUpRefactoringWizard_PageTitle);
  		setWindowTitle(MultiFixMessages.CleanUpRefactoringWizard_WindowTitle);
  		setDefaultPageImageDescriptor(JavaPluginImages.DESC_WIZBAN_CLEAN_UP);
  	}
  
  	/* (non-Javadoc)
  	 * @see org.eclipse.ltk.ui.refactoring.RefactoringWizard#addUserInputPages()
  	 */
  	protected void addUserInputPages() {
  		addPage(new CleanUpConfigurationPage((CleanUpRefactoring)getRefactoring()));
  	}
  
  }
  