/*******************************************************************************
 * Copyright (C) 2003-2007, 2013, Guillaume Brocker
 * 
 * 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:
 *     Guillaume Brocker - Initial API and implementation
 *
 ******************************************************************************/ 

package eclox.ui.editor.advanced;

import java.util.Stack;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;

import eclox.core.doxyfiles.Setting;

/**
 * Implements an action that trigger the navigation in the selection history.
 * This class is used to contribute to the form's action bar manager.
 * 
 * @author Guillaume Brocker
 */
class HistoryAction extends Action {
	
	/**
	 * Implements a menu listener used to trigger selection changes
	 */
	private class MySelectionListener implements SelectionListener {

		/**
		 * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
		 */
		public void widgetDefaultSelected(SelectionEvent e) {
			widgetSelected(e);			
		}

		/**
		 * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
		 */
		public void widgetSelected(SelectionEvent e) {
			assert e.widget instanceof MenuItem;
			
			MenuItem			menuItem = (MenuItem) e.widget;
			NavigableSelection	selection = (NavigableSelection) menuItem.getData();
			
			masterPart.setSelection(selection, true);
		}
		
	}
	
    /**
     * Implements the menu creator tha will create the menu for the action.
     */
	private class MyMenuCreator implements IMenuCreator {
    	
		private Menu menu;

		/**
		 * @see org.eclipse.jface.action.IMenuCreator#dispose()
		 */
		public void dispose() {
			if( menu != null ) {
				menu.dispose();
			}
		}

		/**
		 * @see org.eclipse.jface.action.IMenuCreator#getMenu(org.eclipse.swt.widgets.Control)
		 */
		public Menu getMenu(Control parent) {
			if( menu == null ) {
				menu = new Menu(parent);
			}
			fill(menu);
			return menu;
		}

		/**
		 * @see org.eclipse.jface.action.IMenuCreator#getMenu(org.eclipse.swt.widgets.Menu)
		 */
		public Menu getMenu(Menu parent) {
			if( menu == null ) {
				menu = new Menu(parent);
			}
			fill(menu);
			return menu;
		}
		
		/**
		 * Fills the menu with navigation history.
		 * 
		 * @param menu	the menu to full
		 */
		private void fill(Menu menu) {
			// Clears the menu content.
			MenuItem [] items = menu.getItems();
			for( int i = 0; i != items.length; ++i ) {
				items[i].dispose();
			}
			
			// Fills the menu content.
			NavigableSelection	currentSelection = getFollowingSelection(selection);
			while(currentSelection != null) {
				Setting		setting = (Setting) currentSelection.getFirstElement();
				MenuItem	menuItem = new MenuItem(menu, 0);
				menuItem.setText( setting.hasProperty(Setting.TEXT) ? setting.getProperty(Setting.TEXT) : setting.getIdentifier() );
				menuItem.setData(currentSelection);
				menuItem.addSelectionListener(new MySelectionListener());
				
				currentSelection = getFollowingSelection(currentSelection);
			}
		}
		
		/**
		 * Retrieves the selection following the given one, according
		 * to the current action's direction.
		 * 
		 * @param	selection	a reference selection
		 * 
		 * @return	the following selection or null if none
		 */
		private NavigableSelection getFollowingSelection( NavigableSelection selection ) {
			return (direction == BACK) ? selection.getPreviousSelection() : selection.getNextSelection();
		}
    	
    }

	
	/** defines the back navigation direction */
	public static final int BACK = 0;
	
	/** defines the forward navigation direction */
	public static final int FORWARD = 1;
	
	/** the direction of the navigation assigned to the action */
	private int direction;
	
	/** the master part that holds the nivation history */
	private MasterPart masterPart;
	
	/** the current selection */
	private NavigableSelection selection;
	
	/**
	 * Constructor
	 * 
	 * @param direction		the navigation direction for the action
	 * @param masterPart	the master part that manage the action
	 */
	public HistoryAction(int direction, MasterPart masterPart) {
		super(new String(), IAction.AS_DROP_DOWN_MENU);
		
		assert masterPart != null;
		
		this.direction = direction;
		this.masterPart = masterPart;
		setMenuCreator(new MyMenuCreator());
	}

	/**
	 * @see org.eclipse.jface.action.Action#run()
	 */
	public void run() {
		switch(direction) {
		case BACK:
			masterPart.setSelection( selection.getPreviousSelection(), true );
			break;
		
		case FORWARD:
			masterPart.setSelection( selection.getNextSelection(), true );
			break;
		}
	}
	
	/**
	 * Tells the action that the selection changed
	 * 
	 * @param	newSelection	the new selection
	 */
	public void selectionChanged(ISelection newSelection) {
		assert newSelection instanceof NavigableSelection;
		
		selection = (NavigableSelection) newSelection;
		Stack sideElements = direction == BACK ? selection.getPreviousElements() : selection.getNextElements();
		
		if( sideElements.isEmpty() ) {
			setEnabled(false);
			setText(new String());
		}
		else {
			Setting	setting	= (Setting) sideElements.peek();
			
			setEnabled(true);
			setText("Go to " + setting.getProperty(Setting.TEXT));
		}
	}

}
