/*******************************************************************************
 *  Copyright (c) 2011 GitHub Inc.
 *  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:
 *    Kevin Sawicki (GitHub Inc.) - initial API and implementation
 *******************************************************************************/
package org.eclipse.mylyn.internal.github.ui.issue;

import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.window.Window;
import org.eclipse.mylyn.internal.github.ui.GitHubImages;
import org.eclipse.mylyn.internal.tasks.ui.notifications.TaskDiffUtil;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskDataModel;
import org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor;
import org.eclipse.mylyn.tasks.ui.editors.LayoutHint;
import org.eclipse.mylyn.tasks.ui.editors.LayoutHint.ColumnSpan;
import org.eclipse.mylyn.tasks.ui.editors.LayoutHint.RowSpan;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.forms.widgets.FormToolkit;

/**
 * Editor part for viewing an issue's labels.
 */
public class IssueLabelAttributeEditor extends AbstractAttributeEditor {

	/**
	 * LABEL_WIDTH
	 */
	public static final int LABEL_WIDTH = 80;

	/**
	 * LABEL_COLUMNS
	 */
	public static final int LABEL_COLUMNS = 12;

	private class NewLabelAction extends Action {

		public NewLabelAction() {
			super(Messages.IssueLabelAttributeEditor_ActionNewLabel,
					IAction.AS_PUSH_BUTTON);
		}

		public void run() {
			InputDialog dialog = new InputDialog(getControl().getShell(),
					Messages.IssueLabelAttributeEditor_TitleNewLabel,
					Messages.IssueLabelAttributeEditor_DescriptionNewLabel,
					"", new IInputValidator() { //$NON-NLS-1$

						public String isValid(String newText) {
							if (newText == null || newText.trim().length() == 0)
								return Messages.IssueLabelAttributeEditor_MessageEnterName;
							return null;
						}
					});
			if (Window.OK == dialog.open()
					&& !getTaskAttribute().getValues().contains(
							dialog.getValue())) {
				getTaskAttribute().addValue(dialog.getValue());
				markLabelsChanged();
				refreshLabels();
			}
		}

	}

	private class RemoveLabelAction extends Action {

		private String label;

		public RemoveLabelAction(String label) {
			super(Messages.IssueLabelAttributeEditor_ActionRemoveLabel,
					IAction.AS_PUSH_BUTTON);
			this.label = label;
		}

		public void run() {
			if (getTaskAttribute().getValues().contains(label)) {
				getTaskAttribute().removeValue(label);
				markLabelsChanged();
				refreshLabels();
			}
		}

	}

	private class LabelAction extends Action {

		public LabelAction(String label) {
			super(label, IAction.AS_PUSH_BUTTON);
			setImageDescriptor(GitHubImages.DESC_GITHUB_ISSUE_LABEL);
		}

		public void run() {
			if (!getTaskAttribute().getValues().contains(getText())) {
				getTaskAttribute().addValue(getText());
				markLabelsChanged();
				refreshLabels();
			}
		}
	}

	private Composite displayArea;
	private boolean layout = false;
	private Composite labelsArea;
	private List<CLabel> labelControls = new LinkedList<CLabel>();
	private FormToolkit toolkit;
	private Comparator<String> labelComparator = new Comparator<String>() {

		public int compare(String o1, String o2) {
			return o1.compareToIgnoreCase(o2);
		}
	};

	/**
	 * @param manager
	 * @param taskAttribute
	 */
	public IssueLabelAttributeEditor(TaskDataModel manager,
			TaskAttribute taskAttribute) {
		super(manager, taskAttribute);
		setLayoutHint(new LayoutHint(RowSpan.SINGLE, ColumnSpan.MULTIPLE));
	}

	private void refreshLabels() {
		for (CLabel labelControl : this.labelControls)
			labelControl.dispose();
		this.labelControls.clear();

		Image labelImage = GitHubImages
				.get(GitHubImages.GITHUB_ISSUE_LABEL_OBJ);
		List<String> labels = new LinkedList<String>(getTaskAttribute()
				.getValues());
		Collections.sort(labels, this.labelComparator);
		if (!labels.isEmpty())
			for (final String label : labels) {
				CLabel cLabel = new CLabel(labelsArea, SWT.NONE);
				MenuManager manager = new MenuManager();
				manager.setRemoveAllWhenShown(true);
				manager.addMenuListener(new IMenuListener() {

					public void menuAboutToShow(IMenuManager manager) {
						manager.add(new RemoveLabelAction(label));
					}
				});
				Menu menu = manager.createContextMenu(cLabel);
				cLabel.setMenu(menu);
				String shortened = TaskDiffUtil.shortenText(displayArea, label,
						LABEL_WIDTH);
				cLabel.setImage(labelImage);
				cLabel.setText(shortened);
				cLabel.setForeground(toolkit.getColors().getForeground());
				if (!shortened.equals(label))
					cLabel.setToolTipText(label);
				this.labelControls.add(cLabel);
			}
		else
			this.labelControls.add(new CLabel(labelsArea, SWT.NONE));

		if (this.layout)
			displayArea.getParent().getParent().layout(true, true);
	}

	private void markLabelsChanged() {
		getModel().attributeChanged(getTaskAttribute());
	}

	/**
	 * @see org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor#createControl(org.eclipse.swt.widgets.Composite,
	 *      org.eclipse.ui.forms.widgets.FormToolkit)
	 */
	public void createControl(Composite parent, FormToolkit toolkit) {
		this.toolkit = toolkit;
		displayArea = toolkit.createComposite(parent);
		displayArea.setBackgroundMode(SWT.INHERIT_FORCE);
		GridDataFactory.fillDefaults().grab(true, true).applyTo(displayArea);
		GridLayoutFactory.fillDefaults().numColumns(2).applyTo(displayArea);

		final ToolBar toolbar = new ToolBar(displayArea, SWT.FLAT);
		toolkit.adapt(toolbar, false, false);
		final ToolItem addItem = new ToolItem(toolbar, SWT.DROP_DOWN);
		addItem.setImage(GitHubImages.get(GitHubImages.GITHUB_ADD_OBJ));
		addItem.setToolTipText(Messages.IssueLabelAttributeEditor_TooltipAddLabel);

		MenuManager manager = new MenuManager();
		manager.setRemoveAllWhenShown(true);
		manager.addMenuListener(new IMenuListener() {

			public void menuAboutToShow(IMenuManager manager) {
				manager.add(new NewLabelAction());
				manager.add(new Separator());
				List<String> labels = new LinkedList<String>(getTaskAttribute()
						.getOptions().values());
				labels.removeAll(getTaskAttribute().getValues());
				for (String label : labels)
					manager.add(new LabelAction(label));
				manager.update();
			}
		});
		final Menu menu = manager.createContextMenu(displayArea);
		addItem.addSelectionListener(new SelectionAdapter() {

			public void widgetSelected(SelectionEvent e) {
				Rectangle toolItemBounds = addItem.getBounds();
				Point location = toolbar.toDisplay(toolItemBounds.x,
						toolItemBounds.y + toolItemBounds.height);
				menu.setLocation(location);
				menu.setVisible(true);
			}

		});

		labelsArea = toolkit.createComposite(displayArea);
		labelsArea.setBackgroundMode(SWT.INHERIT_FORCE);
		labelsArea.setBackground(null);
		GridLayoutFactory.fillDefaults().numColumns(LABEL_COLUMNS)
				.applyTo(labelsArea);
		GridDataFactory.swtDefaults().grab(true, true).applyTo(labelsArea);
		refreshLabels();
		setControl(displayArea);
		layout = true;
	}
}