content: /**
   *  Copyright (c) 2013-2016 Angelo ZERR.
   *  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:
   *  Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
   */
  package tern.eclipse.ide.ui.controls;
  
  import java.util.ArrayList;
  import java.util.Collection;
  
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.runtime.Platform;
  import org.eclipse.core.runtime.preferences.DefaultScope;
  import org.eclipse.core.runtime.preferences.IScopeContext;
  import org.eclipse.core.runtime.preferences.InstanceScope;
  import org.eclipse.jface.dialogs.Dialog;
  import org.eclipse.jface.dialogs.IDialogSettings;
  import org.eclipse.jface.dialogs.MessageDialog;
  import org.eclipse.jface.viewers.ArrayContentProvider;
  import org.eclipse.jface.viewers.CheckStateChangedEvent;
  import org.eclipse.jface.viewers.CheckboxTableViewer;
  import org.eclipse.jface.viewers.ICheckStateListener;
  import org.eclipse.jface.viewers.ISelectionChangedListener;
  import org.eclipse.jface.viewers.IStructuredSelection;
  import org.eclipse.jface.viewers.SelectionChangedEvent;
  import org.eclipse.jface.viewers.StructuredSelection;
  import org.eclipse.jface.viewers.TableViewerColumn;
  import org.eclipse.jface.window.Window;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.graphics.Font;
  import org.eclipse.swt.layout.GridData;
  import org.eclipse.swt.layout.GridLayout;
  import org.eclipse.swt.widgets.Composite;
  import org.eclipse.swt.widgets.Control;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.swt.widgets.Table;
  
  import tern.eclipse.ide.core.IIDETernRepository;
  import tern.eclipse.ide.core.TernCorePlugin;
  import tern.eclipse.ide.core.preferences.TernCorePreferenceConstants;
  import tern.eclipse.ide.internal.ui.TernUIMessages;
  import tern.eclipse.ide.internal.ui.dialogs.EditRepositoryDialog;
  import tern.eclipse.ide.ui.TernUIPlugin;
  import tern.eclipse.ide.ui.viewers.TernRepositoryLabelProvider;
  import tern.repository.ITernRepository;
  import tern.server.ITernModule;
  import tern.utils.TernModuleHelper;
  
  /**
   * Tern repository block.
   * 
   */
  public class TernRepositoryBlock extends AbstractTableBlock {
  
  	private CheckboxTableViewer repositoryViewer;
  	private final IProject project;
  	private TernModulesBlock modulesBlock;
  
  	public TernRepositoryBlock(IProject project) {
  		this.project = project;
  	}
  
  	public Control createControl(Composite ancestor) {
  
  		Composite parent = new Composite(ancestor, SWT.BORDER);
  		GridLayout layout = new GridLayout();
  		layout.numColumns = 1;
  		layout.marginHeight = 0;
  		layout.marginWidth = 0;
  		parent.setLayout(layout);
  		Font font = ancestor.getFont();
  		parent.setFont(font);
  		parent.setLayoutData(new GridData(GridData.FILL_BOTH));
  
  		createRepositoryTable(parent);
  		createModulesTable(parent);
  
  		Dialog.applyDialogFont(parent);
  		return parent;
  	}
  
  	private void createRepositoryTable(Composite parent) {
  
  		Table table = new Table(parent, SWT.CHECK | SWT.SINGLE | SWT.BORDER
  				| SWT.FULL_SELECTION | SWT.V_SCROLL);
  
  		GridData data = new GridData(GridData.FILL_BOTH);
  		table.setLayoutData(data);
  		table.setFont(parent.getFont());
  
  		table.setHeaderVisible(true);
  		table.setLinesVisible(false);
  
  		repositoryViewer = new CheckboxTableViewer(table);
  
  		// create name column
  		TableViewerColumn nameColumn = new TableViewerColumn(repositoryViewer,
  				SWT.NONE);
  		nameColumn.getColumn().setWidth(100);
  		nameColumn.getColumn().setResizable(true);
  		nameColumn.getColumn().setText(
  				TernUIMessages.TernRepositoryBlock_repositoryName);
  
  		// create name column
  		TableViewerColumn filenameColumn = new TableViewerColumn(
  				repositoryViewer, SWT.NONE);
  		filenameColumn.getColumn().setWidth(300);
  		filenameColumn.getColumn().setResizable(true);
  		filenameColumn.getColumn().setText(
  				TernUIMessages.TernRepositoryBlock_filenameColumn);
  
  		repositoryViewer.setLabelProvider(TernRepositoryLabelProvider
  				.getInstance());
  		repositoryViewer.setContentProvider(ArrayContentProvider.getInstance());
  
  		addSelectionChangedListener(new ISelectionChangedListener() {
  
  			@Override
  			public void selectionChanged(SelectionChangedEvent event) {
  				refreshModules();
  			}
  
  		});
  
  		repositoryViewer.addCheckStateListener(new ICheckStateListener() {
  
  			@Override
  			public void checkStateChanged(CheckStateChangedEvent event) {
  				IIDETernRepository repository = (IIDETernRepository) event
  						.getElement();
  				// check and select only one tern repository.
  				checkAndSelect(repository);
  			}
  		});
  		restoreColumnSettings();
  	}
  
  	public void addSelectionChangedListener(ISelectionChangedListener listener) {
  		repositoryViewer.addSelectionChangedListener(listener);
  	}
  
  	private void createModulesTable(Composite parent) {
  		GridLayout layout = new GridLayout();
  		layout.numColumns = 1;
  		layout.marginHeight = 0;
  		layout.marginWidth = 0;
  		parent.setLayout(layout);
  
  		// create UI modules
  		modulesBlock = new TernModulesBlock(project,
  				TernUIMessages.TernRepositoryBlock_modules_desc);
  		Control control = modulesBlock.createControl(parent);
  		GridData data = new GridData(GridData.FILL_BOTH);
  		data.horizontalSpan = 1;
  		control.setLayoutData(data);
  
  	}
  
  	private void refreshModules() {
  		IStructuredSelection selection = (IStructuredSelection) repositoryViewer
  				.getSelection();
  		if (!selection.isEmpty()) {
  			ITernRepository repository = (ITernRepository) selection
  					.getFirstElement();
  			refreshModules(repository);
  		}
  	}
  
  	private void refreshModules(ITernRepository repository) {
  		IScopeContext[] lookupOrder = new IScopeContext[] {
  				InstanceScope.INSTANCE, DefaultScope.INSTANCE };
  		String moduleNames = Platform.getPreferencesService().getString(
  				TernCorePlugin.getDefault().getBundle().getSymbolicName(),
  				TernCorePreferenceConstants.DEFAULT_TERN_MODULES,
  				TernCorePreferenceConstants.DEFAULT_TERN_MODULES_VALUE,
  				lookupOrder);
  		modulesBlock.loadModules(repository, moduleNames.split(","));
  	}
  
  	public void setCheckedModules(String[] selectedModules) {
  		modulesBlock.loadModules(getCurrentRepository(), selectedModules);
  	}
  
  	@Override
  	protected Table getTable() {
  		return repositoryViewer.getTable();
  	}
  
  	@Override
  	protected IDialogSettings getDialogSettings() {
  		return TernUIPlugin.getDefault().getDialogSettings();
  	}
  
  	@Override
  	protected String getQualifier() {
  		return TernUIPlugin.PLUGIN_ID + ".repository.";
  	}
  
  	public void loadRepositories() {
  		IIDETernRepository checkedRepository = null;
  		IIDETernRepository currentRepository = TernCorePlugin
  				.getTernRepositoryManager().getRepository(project);
  		// clone the list of tern repository.
  		Collection<IIDETernRepository> repositories = new ArrayList<IIDETernRepository>();
  		IIDETernRepository clonedRepository = null;
  		for (IIDETernRepository repository : TernCorePlugin
  				.getTernRepositoryManager().getRepositories()) {
  			clonedRepository = repository.isDefault() ? repository
  					: repository.copy();
  			if (repository.equals(currentRepository)) {
  				checkedRepository = clonedRepository;
  			}
  			repositories.add(clonedRepository);
  		}
  		// refresh the viewer
  		repositoryViewer.setInput(repositories);
  		// check the default tern repository
  		if (checkedRepository != null) {
  			setCheckedRepository(checkedRepository);
  		}
  	}
  
  	/**
  	 * Check and select the given tern repository.
  	 * 
  	 * @param repository
  	 *            the tern repository to check.
  	 */
  	public void setCheckedRepository(IIDETernRepository repository) {
  		if (repository != null) {
  			checkAndSelect(repository);
  		}
  	}
  
  	/**
  	 * Returns the checked tern repository.
  	 * 
  	 * @return the checked tern repository.
  	 */
  	public ITernRepository getCheckedRepository() {
  		Object[] elements = repositoryViewer.getCheckedElements();
  		return (ITernRepository) elements[0];
  	}
  
  	/**
  	 * Create and add a new tern repository.
  	 * 
  	 * @param parentShell
  	 */
  	public void addRepository(Shell parentShell) {
  		EditRepositoryDialog dialog = new EditRepositoryDialog(parentShell,
  				getRepositories());
  		if (dialog.open() == Window.OK) {
  			IIDETernRepository newTernRepository = dialog.getRepository();
  			if (newTernRepository != null) {
  				getRepositories().add(newTernRepository);
  				refresh();
  			}
  		}
  	}
  
  	/**
  	 * Remove the current repository.
  	 * 
  	 * @param parentShell
  	 */
  	public void removeRepository(Shell parentShell) {
  		if (MessageDialog.openConfirm(parentShell,
  				TernUIMessages.TernRepositoryBlock_removeRepository_title,
  				TernUIMessages.TernRepositoryBlock_removeRepository_message)) {
  			ITernRepository repository = getCurrentRepository();
  			if (repository != null) {
  				getRepositories().remove(repository);
  				refresh();
  			}
  		}
  	}
  
  	/**
  	 * Refresh the current repository.
  	 * 
  	 */
  	public void refreshRepository() {
  		ITernRepository repository = getCurrentRepository();
  		if (repository != null) {
  			repository.refresh();
  			refreshModules();
  		}
  	}
  
  	/**
  	 * Edit the current repository.
  	 * 
  	 * @param parentShell
  	 */
  	public void editRepository(Shell parentShell) {
  		IIDETernRepository repository = getCurrentRepository();
  		if (repository != null && !repository.isDefault()) {
  			EditRepositoryDialog dialog = new EditRepositoryDialog(parentShell,
  					getRepositories(), repository);
  			if (dialog.open() == Window.OK) {
  				repositoryViewer.refresh(repository);
  				repository.refresh();
  				refreshModules();
  			}
  		}
  	}
  
  	/**
  	 * Returns the cloned tern repository.
  	 * 
  	 * @return
  	 */
  	private Collection<IIDETernRepository> getRepositories() {
  		return (Collection<IIDETernRepository>) repositoryViewer.getInput();
  	}
  
  	/**
  	 * Refresh tern repository and linked modules.
  	 */
  	private void refresh() {
  		repositoryViewer.refresh();
  		refreshModules();
  	}
  
  	/**
  	 * Save repositories.
  	 */
  	public void saveRepositories() {
  		// save repositories
  		TernCorePlugin.getTernRepositoryManager().setRepositories(
  				getRepositories());
  		saveDefaultModules();
  	}
  
  	public void saveDefaultModules() {
  		// save default modules
  		new InstanceScope().getNode(
  				TernCorePlugin.getDefault().getBundle().getSymbolicName()).put(
  				TernCorePreferenceConstants.DEFAULT_TERN_MODULES,
  				getDefaultModules());
  	}
  
  	private String getDefaultModules() {
  		ITernModule[] modules = modulesBlock.getCheckedModules().toArray(
  				ITernModule.EMPTY_MODULE);
  		return TernModuleHelper.getModulesAsString(modules);
  	}
  
  	/**
  	 * Returns the current repository.
  	 * 
  	 * @return the current repository.
  	 */
  	private IIDETernRepository getCurrentRepository() {
  		IStructuredSelection selection = (IStructuredSelection) repositoryViewer
  				.getSelection();
  		if (selection.isEmpty()) {
  			return null;
  		}
  		return (IIDETernRepository) selection.getFirstElement();
  	}
  
  	/**
  	 * Check and select the single given tern repository.
  	 * 
  	 * @param repository
  	 *            the repository to select and check.
  	 */
  	private void checkAndSelect(IIDETernRepository repository) {
  		repositoryViewer.setCheckedElements(new Object[] { repository });
  		repositoryViewer.setSelection(new StructuredSelection(repository));
  	}
  
  }
  