/*******************************************************************************
 * Copyright (c) 2004, 2009 Frank Becker 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:
 *     Frank Becker - initial API and implementation
 *******************************************************************************/

package org.eclipse.mylyn.internal.tasks.ui.dialogs;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.mylyn.internal.tasks.ui.util.SortCriterion;
import org.eclipse.mylyn.internal.tasks.ui.util.TaskComparator;
import org.eclipse.mylyn.internal.tasks.ui.util.SortCriterion.SortKey;
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.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.dialogs.SelectionDialog;

/**
 * @author FrankBecker
 */
public class TaskCompareDialog extends SelectionDialog {

	private Combo[] priorityCombos;

	private Button[] ascendingButtons;

	private Button[] descendingButtons;

	private final String[] propertyText;

	private boolean dirty = false;

	private final TaskComparator taskComparator;

	private String selectedValueLastCombo;

	public TaskCompareDialog(IShellProvider parentShell, TaskComparator taskComparator) {
		super(parentShell.getShell());
		SortCriterion.SortKey[] values = SortCriterion.SortKey.values();
		propertyText = new String[values.length];
		for (int i = 0; i < values.length; i++) {
			propertyText[i] = values[i].getLabel();
		}
		this.taskComparator = taskComparator;
		setTitle(Messages.TaskCompareDialog_Sorting);
	}

	@Override
	protected Control createDialogArea(Composite parent) {
		Composite composite = (Composite) super.createDialogArea(parent);
		initializeDialogUnits(composite);
		Control control = createContentArea(composite);
		GridDataFactory.fillDefaults().grab(true, true).applyTo(control);
		Dialog.applyDialogFont(parent);
		return composite;
	}

	protected Control createContentArea(Composite parent) {
		Group prioritiesArea = new Group(parent, SWT.NONE);
		prioritiesArea.setLayout(new GridLayout(3, false));
		prioritiesArea.setText(Messages.TaskCompareDialog_Tasks);

		ascendingButtons = new Button[SortCriterion.kindCount];
		descendingButtons = new Button[SortCriterion.kindCount];
		priorityCombos = new Combo[SortCriterion.kindCount];

		for (int i = 0; i < SortCriterion.kindCount; i++) {
			final int index = i;
			Label numberLabel = new Label(prioritiesArea, SWT.NONE);
			if (i == 0) {
				numberLabel.setText(Messages.TaskCompareDialog_Sort_by);
			} else {
				numberLabel.setText(Messages.TaskCompareDialog_Then_by);
			}
//			numberLabel.setText("" + (i + 1) + "."); //$NON-NLS-1$ //$NON-NLS-2$
			priorityCombos[i] = new Combo(prioritiesArea, SWT.READ_ONLY);
			priorityCombos[i].setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

			Composite directionGroup = new Composite(prioritiesArea, SWT.NONE);
			directionGroup.setLayout(new GridLayout(2, false));
			ascendingButtons[i] = new Button(directionGroup, SWT.RADIO);
			ascendingButtons[i].setText(Messages.TaskCompareDialog_Ascending);
			ascendingButtons[i].addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					markDirty();
				}
			});
			descendingButtons[i] = new Button(directionGroup, SWT.RADIO);
			descendingButtons[i].setText(Messages.TaskCompareDialog_Descending);
			descendingButtons[i].addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					markDirty();
				}
			});
			if (i < priorityCombos.length) {
				priorityCombos[i].addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
//						int oldSelectionDirection = 1;
//						if (descendingButtons[index].getSelection()) {
//							oldSelectionDirection = -1;
//						}
						ArrayList<String> oldSelectionList = new ArrayList<String>(
								Arrays.asList(priorityCombos[index].getItems()));
						String oldSelection;
						if (index + 1 == SortCriterion.kindCount) {
							oldSelection = selectedValueLastCombo;
						} else {
							oldSelectionList.removeAll(Arrays.asList(priorityCombos[index + 1].getItems()));
							oldSelection = propertyText[SortKey.NONE.ordinal()];
							if (oldSelectionList.size() == 1) {
								oldSelection = oldSelectionList.get(0);
							}
						}
						String newSelection = priorityCombos[index].getItem(priorityCombos[index].getSelectionIndex());
						if (oldSelection.equals(newSelection)) {
							return;
						}
						if (index + 1 == SortCriterion.kindCount) {
							selectedValueLastCombo = newSelection;
						}
						if (oldSelection.equals(propertyText[SortKey.NONE.ordinal()])) {
							ascendingButtons[index].setEnabled(true);
							descendingButtons[index].setEnabled(true);
							if (index + 1 < SortCriterion.kindCount) {
								priorityCombos[index + 1].setEnabled(true);
								ArrayList<String> availablePriorities = new ArrayList<String>(
										Arrays.asList(priorityCombos[index].getItems()));
								availablePriorities.remove(newSelection);
								for (int k = index + 1; k < SortCriterion.kindCount; k++) {
									priorityCombos[k].removeAll();
									for (int j = 0; j < availablePriorities.size(); j++) {
										priorityCombos[k].add(availablePriorities.get(j));
									}
									priorityCombos[k].select(priorityCombos[k].indexOf(propertyText[SortKey.NONE.ordinal()]));
								}
							}
						} else if (newSelection.equals(propertyText[SortKey.NONE.ordinal()])) {
							ascendingButtons[index].setEnabled(false);
							descendingButtons[index].setEnabled(false);
							if (index + 1 < SortCriterion.kindCount) {
								ArrayList<String> availablePriorities = new ArrayList<String>(
										Arrays.asList(priorityCombos[index].getItems()));
								for (int k = index + 1; k < SortCriterion.kindCount; k++) {
									priorityCombos[k].setEnabled(true);
									priorityCombos[k].removeAll();
									for (int j = 0; j < availablePriorities.size(); j++) {
										priorityCombos[k].add(availablePriorities.get(j));
									}
									priorityCombos[k].select(priorityCombos[k].indexOf(propertyText[SortKey.NONE.ordinal()]));
									priorityCombos[k].setEnabled(false);
									ascendingButtons[k].setEnabled(false);
									descendingButtons[k].setEnabled(false);
								}
							}
						} else {
							for (int j = index + 1; j < priorityCombos.length; j++) {
								int newSelectionIndex = priorityCombos[j].indexOf(newSelection);
								//this combo's current selection is equal to newSelection
								if (priorityCombos[j].getSelectionIndex() == newSelectionIndex) {
									priorityCombos[j].remove(newSelection);
									int insertionPoint = -1
											- Arrays.binarySearch(priorityCombos[j].getItems(), oldSelection,
													columnComparator);
									if (insertionPoint >= 0 && insertionPoint <= priorityCombos[j].getItemCount()) {
										priorityCombos[j].add(oldSelection, insertionPoint);
									} else {
										priorityCombos[j].add(oldSelection);
									}
									priorityCombos[j].select(priorityCombos[j].indexOf(oldSelection));
// remove the comment if you want to move the current ascending/descending 								
//									ascendingButtons[index].setSelection(ascendingButtons[j].getSelection());
//									descendingButtons[index].setSelection(descendingButtons[j].getSelection());
//									ascendingButtons[j].setSelection(oldSelectionDirection == 1);
//									descendingButtons[j].setSelection(oldSelectionDirection == -1);
								}
								//this combo contains newSelection
								else if (newSelectionIndex >= 0) {
									String currentText = priorityCombos[j].getText();
									priorityCombos[j].remove(newSelection);
									int insertionPoint = -1
											- Arrays.binarySearch(priorityCombos[j].getItems(), oldSelection,
													columnComparator);
									if (insertionPoint >= 0 && insertionPoint <= priorityCombos[j].getItemCount()) {
										priorityCombos[j].add(oldSelection, insertionPoint);
										priorityCombos[j].select(priorityCombos[j].indexOf(currentText));
									} else {
										priorityCombos[j].add(oldSelection);
									}
								}
							}
						}
						markDirty();
					}
				});
			} else {
				priorityCombos[i].addSelectionListener(new SelectionAdapter() {
					@Override
					public void widgetSelected(SelectionEvent e) {
						markDirty();
					}
				});
			}

		}
		updateUI();
		return prioritiesArea;
	}

	@Override
	protected void okPressed() {
		if (isDirty()) {
			for (int i = 0; i < SortCriterion.kindCount; i++) {
				SortCriterion keyEntries = taskComparator.getSortCriterion(i);
				keyEntries.setKey(SortKey.valueOfLabel(priorityCombos[i].getText()));
				if (descendingButtons[i].getSelection()) {
					keyEntries.setDirection(-1);
				} else {
					keyEntries.setDirection(1);
				}
			}
		}
		super.okPressed();
	}

	protected boolean isDirty() {
		return dirty;
	}

	/**
	 * Sets the dirty flag to true.
	 */
	protected void markDirty() {
		dirty = true;
	}

	private final Comparator<String> columnComparator = new Comparator<String>() {
		public int compare(String arg0, String arg1) {
			int index0 = -1;
			int index1 = -1;
			for (int i = 0; i < propertyText.length; i++) {
				if (propertyText[i].equals(arg0)) {
					index0 = i;
				}
				if (propertyText[i].equals(arg1)) {
					index1 = i;
				}
			}
			return index0 - index1;
		}
	};

	protected void updateUI() {
		ArrayList<String> availablePriorities = new ArrayList<String>(Arrays.asList(propertyText));
		for (int i = 0; i < TaskComparator.CRITERIA_COUNT; i++) {
			SortCriterion criterion = taskComparator.getSortCriterion(i);
			priorityCombos[i].removeAll();
			for (int j = 0; j < availablePriorities.size(); j++) {
				priorityCombos[i].add(availablePriorities.get(j));
			}
			priorityCombos[i].select(priorityCombos[i].indexOf(propertyText[criterion.getKey().ordinal()]));
			ascendingButtons[i].setSelection(criterion.getDirection() == 1);
			descendingButtons[i].setSelection(criterion.getDirection() == -1);
			if (i == TaskComparator.CRITERIA_COUNT - 1) {
				selectedValueLastCombo = propertyText[criterion.getKey().ordinal()];
			}
			if (criterion.getKey() != SortKey.NONE) {
				availablePriorities.remove(propertyText[criterion.getKey().ordinal()]);
			} else {
				ascendingButtons[i].setEnabled(false);
				descendingButtons[i].setEnabled(false);
				for (int k = i + 1; k < TaskComparator.CRITERIA_COUNT; k++) {
					for (int j = 0; j < availablePriorities.size(); j++) {
						priorityCombos[k].add(availablePriorities.get(j));
					}
					priorityCombos[k].select(priorityCombos[k].indexOf(propertyText[SortKey.NONE.ordinal()]));
					if (k == TaskComparator.CRITERIA_COUNT - 1) {
						selectedValueLastCombo = propertyText[SortKey.NONE.ordinal()];
					}
					ascendingButtons[k].setSelection(taskComparator.getSortCriterion(k).getDirection() == 1);
					descendingButtons[k].setSelection(taskComparator.getSortCriterion(k).getDirection() == -1);
					priorityCombos[k].setEnabled(false);
					ascendingButtons[k].setEnabled(false);
					descendingButtons[k].setEnabled(false);
				}
				break;
			}
		}
	}

}
