/*******************************************************************************
 * Copyright (c) 2004, 2009 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
 *     Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 145557 [WorkbenchParts] Content description label needs a hover 
 *     Semion Chichelnitsky <semion@il.ibm.com> - Bug 66889 [ViewMgmt] Package explorer message clipped
 *******************************************************************************/
package org.eclipse.ui.internal.presentations.defaultpresentation;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.util.Geometry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabFolderEvent;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
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.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
import org.eclipse.ui.internal.WorkbenchImages;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.dnd.DragUtil;
import org.eclipse.ui.internal.presentations.PaneFolder;
import org.eclipse.ui.internal.presentations.PaneFolderButtonListener;
import org.eclipse.ui.internal.presentations.util.AbstractTabFolder;
import org.eclipse.ui.internal.presentations.util.AbstractTabItem;
import org.eclipse.ui.internal.presentations.util.PartInfo;
import org.eclipse.ui.internal.presentations.util.TabFolderEvent;
import org.eclipse.ui.internal.util.Util;

/**
 * @since 3.1
 */
public class DefaultTabFolder extends AbstractTabFolder {

    private PaneFolder paneFolder;
    private Control viewToolBar;
    private Label titleLabel;
    
    private PaneFolderButtonListener buttonListener = new PaneFolderButtonListener() {
        public void stateButtonPressed(int buttonId) {
            fireEvent(TabFolderEvent.stackStateToEventId(buttonId));
        }

        /**
         * Called when a close button is pressed.
         *   
         * @param item the tab whose close button was pressed
         */
        public void closeButtonPressed(CTabItem item) {
            fireEvent(TabFolderEvent.EVENT_CLOSE, getTab(item));
        }
        /**
         * 
         * @since 3.0
         */
        public void showList(CTabFolderEvent event) {
            event.doit = false;
            fireEvent(TabFolderEvent.EVENT_SHOW_LIST);
        }
    };
    
    private Listener selectionListener = new Listener() {
        public void handleEvent(Event e) {
            AbstractTabItem item = getTab((CTabItem) e.item);

            if (item != null) {
                fireEvent(TabFolderEvent.EVENT_TAB_SELECTED, item);
            }
        }
    };
    
    private static DefaultTabFolderColors defaultColors = new DefaultTabFolderColors();
    
    private DefaultTabFolderColors[] activeShellColors = {defaultColors, defaultColors, defaultColors};
    private DefaultTabFolderColors[] inactiveShellColors = {defaultColors, defaultColors, defaultColors};
    private boolean shellActive = false;
    
    /**
     * Create a new instance of the receiver
     * 
     * @param parent
     * @param flags
     * @param allowMin
     * @param allowMax
     */
    public DefaultTabFolder(Composite parent, int flags, boolean allowMin, boolean allowMax) {
        paneFolder = new PaneFolder(parent, flags | SWT.NO_BACKGROUND);
        paneFolder.addButtonListener(buttonListener);
        paneFolder.setMinimizeVisible(allowMin);
        paneFolder.setMaximizeVisible(allowMax);
        paneFolder.getControl().addListener(SWT.Selection, selectionListener);
        paneFolder.setTopRight(null);
        
        // Initialize view menu dropdown
        {            
            ToolBar actualToolBar = new ToolBar(paneFolder.getControl(), SWT.FLAT | SWT.NO_BACKGROUND);
            viewToolBar = actualToolBar;
            
        	actualToolBar.getAccessible().addAccessibleListener(new AccessibleAdapter() {
            	public void getName(AccessibleEvent e) {
            		e.result = WorkbenchMessages.ViewMenu;
            	}
            });
        	
	        ToolItem pullDownButton = new ToolItem(actualToolBar, SWT.PUSH);
	        Image hoverImage = WorkbenchImages
	                .getImage(IWorkbenchGraphicConstants.IMG_LCL_RENDERED_VIEW_MENU);
	        pullDownButton.setDisabledImage(hoverImage);
	        pullDownButton.setImage(hoverImage);
	        pullDownButton.setToolTipText(WorkbenchMessages.ViewMenu); 
            actualToolBar.addMouseListener(new MouseAdapter() {
                public void mouseDown(MouseEvent e) {
                    fireEvent(TabFolderEvent.EVENT_PANE_MENU, getSelection(), getPaneMenuLocation());
                }
            });
            pullDownButton.addSelectionListener(new SelectionAdapter() {
            	public void widgetSelected(SelectionEvent e) {
                    fireEvent(TabFolderEvent.EVENT_PANE_MENU, getSelection(), getPaneMenuLocation());

            		super.widgetSelected(e);
            	}
            });
        }
        
        // Initialize content description label
        {
	        titleLabel = new Label(paneFolder.getControl(), SWT.NONE);
	        titleLabel.moveAbove(null);
	        titleLabel.setVisible(false);
            attachListeners(titleLabel, false);
        }
        
        attachListeners(paneFolder.getControl(), false);
        attachListeners(paneFolder.getViewForm(), false);
        
        paneFolder.setTabHeight(computeTabHeight());
        
        viewToolBar.moveAbove(null);
    }

    /**
     * Changes the minimum number of characters to display in the pane folder
     * tab. This control how much information will be displayed to the user.
     * 
     * @param count
     *            The number of characters to display in the tab folder; this
     *            value should be a positive integer.
     * @see org.eclipse.swt.custom.CTabFolder#setMinimumCharacters(int)
     * @since 3.1
     */
    public void setMinimumCharacters(int count) {
        paneFolder.setMinimumCharacters(count);
    }
    
    public void setSimpleTabs(boolean simple) {
        paneFolder.setSimpleTab(simple);
    }
    
    /**
     * @param item
     * @return
     * @since 3.1
     */
    protected DefaultTabItem getTab(CTabItem item) {
        return (DefaultTabItem)item.getData();
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#computeSize(int, int)
     */
    public Point computeSize(int widthHint, int heightHint) {
        return paneFolder.computeMinimumSize();
    }

    /* package */ PaneFolder getFolder() {
        return paneFolder;
    }
    
    public AbstractTabItem getSelection() {
        return getTab(paneFolder.getSelection());
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#add(int)
     */
    public AbstractTabItem add(int index, int flags) {
        DefaultTabItem result = new DefaultTabItem((CTabFolder)getFolder().getControl(), index, flags);
        
        result.getWidget().setData(result);
        
        return result;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getContentParent()
     */
    public Composite getContentParent() {
        return paneFolder.getContentParent();
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setContent(org.eclipse.swt.widgets.Control)
     */
    public void setContent(Control newContent) {
        paneFolder.setContent(newContent);
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getItems()
     */
    public AbstractTabItem[] getItems() {
        CTabItem[] items = paneFolder.getItems();
        
        AbstractTabItem[] result = new AbstractTabItem[items.length];
        
        for (int i = 0; i < result.length; i++) {
            result[i] = getTab(items[i]);
        }
        
        return result;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getItemCount()
     */
    public int getItemCount() {
        // Override retrieving all the items when we just want the count.
        return paneFolder.getItemCount();
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setSelection(org.eclipse.ui.internal.presentations.util.AbstractTabItem)
     */
    public void setSelection(AbstractTabItem toSelect) {
        paneFolder.setSelection(indexOf(toSelect));
    }

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.ui.internal.presentations.util.AbstractTabFolder#showItem
	 * (org.eclipse.ui.internal.presentations.util.AbstractTabItem)
	 */
	public void showItem(AbstractTabItem toSelect) {
		// overrides default
		int index = indexOf(toSelect);
		if (index != -1)
			paneFolder.showItem(index);
	}

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getToolbarParent()
     */
    public Composite getToolbarParent() {
        return paneFolder.getControl();
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getControl()
     */
    public Control getControl() {
        return paneFolder.getControl();
    }
    
    public void setUnselectedCloseVisible(boolean visible) {
        paneFolder.setUnselectedCloseVisible(visible);
    }

    public void setUnselectedImageVisible(boolean visible) {
        paneFolder.setUnselectedImageVisible(visible);
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getTabArea()
     */
    public Rectangle getTabArea() {
        return Geometry.toDisplay(paneFolder.getControl(), paneFolder.getTitleArea());
    }

    /**
     * @param enabled
     * @since 3.1
     */
    public void enablePaneMenu(boolean enabled) {
        if (enabled) {
            paneFolder.setTopRight(viewToolBar);
            viewToolBar.setVisible(true);
        } else {
            paneFolder.setTopRight(null);
            viewToolBar.setVisible(false);
        }
    }

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setSelectedInfo
	 * (org.eclipse.ui.internal.presentations.util.PartInfo)
	 */
	public void setSelectedInfo(PartInfo info) {
		String newTitle = DefaultTabItem
				.escapeAmpersands(info.contentDescription);

		if (!Util.equals(titleLabel.getText(), newTitle)) {
			titleLabel.setText(newTitle);
			titleLabel.setToolTipText(newTitle);
		}

		if (!info.contentDescription.equals(Util.ZERO_LENGTH_STRING)) {
			paneFolder.flushTopLeftSize();
			paneFolder.setTopLeft(titleLabel);
			titleLabel.setVisible(true);
		} else {
			paneFolder.setTopLeft(null);
			titleLabel.setVisible(false);
		}
	}

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getPaneMenuLocation()
     */
    public Point getPaneMenuLocation() {
        Point toolbarSize = viewToolBar.getSize();
        
        return viewToolBar.toDisplay(0,toolbarSize.y);
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getPartListLocation()
     */
    public Point getPartListLocation() {
        return paneFolder.getControl().toDisplay(paneFolder.getChevronLocation());
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getSystemMenuLocation()
     */
    public Point getSystemMenuLocation() {
        Rectangle bounds = DragUtil.getDisplayBounds(paneFolder.getControl());
		
		int idx = paneFolder.getSelectionIndex();
		if (idx > -1) {
		    CTabItem item = paneFolder.getItem(idx);
		    Rectangle itemBounds = item.getBounds();
		
		    bounds.x += itemBounds.x;
		    bounds.y += itemBounds.y;
		}
		
		Point location = new Point(bounds.x, bounds.y
		        + paneFolder.getTabHeight());
		
		return location;
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#isOnBorder(org.eclipse.swt.graphics.Point)
     */
    public boolean isOnBorder(Point toTest) {
        Control content = paneFolder.getContent();
        if (content != null) {
            Rectangle displayBounds = DragUtil.getDisplayBounds(content);
            
            if (paneFolder.getTabPosition() == SWT.TOP) {
                return toTest.y >= displayBounds.y;
            }
            
            if (toTest.y >= displayBounds.y && toTest.y < displayBounds.y + displayBounds.height) {
                return true;
            }
        }
        
        return super.isOnBorder(toTest);
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#layout(boolean)
     */
    public void layout(boolean flushCache) {
        paneFolder.layout(flushCache);
        super.layout(flushCache);
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setState(int)
     */
    public void setState(int state) {
        paneFolder.setState(state);
        super.setState(state);
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setActive(int)
     */
    public void setActive(int activeState) {
        super.setActive(activeState);
        updateColors();
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setTabPosition(int)
     */
    public void setTabPosition(int tabPosition) {
        paneFolder.setTabPosition(tabPosition);
        super.setTabPosition(tabPosition);
        layout(true);
    }
    
    public void flushToolbarSize() {
        paneFolder.flushTopCenterSize();
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setToolbar(org.eclipse.swt.widgets.Control)
     */
    public void setToolbar(Control toolbarControl) {
        paneFolder.setTopCenter(toolbarControl);
        super.setToolbar(toolbarControl);
    }
    
    public void setColors(DefaultTabFolderColors colors, int activationState, boolean shellActivationState) {
        Assert.isTrue(activationState < activeShellColors.length);
                
        if (shellActivationState) {
            activeShellColors[activationState] = colors;
        } else {
            inactiveShellColors[activationState] = colors;
        }
        
        if (activationState == getActive() && shellActive == shellActivationState) {
            updateColors();
        }
    }
    
    /**
     * 
     * @since 3.1
     */
    public void updateColors() {
        DefaultTabFolderColors currentColors = shellActive ? 
                activeShellColors[getActive()] 
                : inactiveShellColors[getActive()];
                
        paneFolder.setSelectionForeground(currentColors.foreground);
        paneFolder.setSelectionBackground(currentColors.background, currentColors.percentages, currentColors.vertical);
    }

    public void setColors(DefaultTabFolderColors colors, int activationState) {
        setColors(colors, activationState, true);
        setColors(colors, activationState, false);
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#shellActive(boolean)
     */
    public void shellActive(boolean isActive) {
        this.shellActive = isActive;
        super.shellActive(isActive);
        
        updateColors();
    }

    /**
     * @param font
     * @since 3.1
     */
    public void setFont(Font font) {
        if (font != paneFolder.getControl().getFont()) {
            paneFolder.getControl().setFont(font);
            layout(true);
            paneFolder.setTabHeight(computeTabHeight());
        }
    }
    
    /**
     * @return the required tab height for this folder.
     */
    protected int computeTabHeight() {
        GC gc = new GC(getControl());

        // Compute the tab height
        int tabHeight = Math.max(viewToolBar.computeSize(SWT.DEFAULT,
                SWT.DEFAULT).y, gc.getFontMetrics().getHeight());

        gc.dispose();

        return tabHeight;
    }

    /**
     * @param b
     * @since 3.1
     */
    public void setSingleTab(boolean b) {
        paneFolder.setSingleTab(b);
        AbstractTabItem[] items = getItems();
        
        for (int i = 0; i < items.length; i++) {
            DefaultTabItem item = (DefaultTabItem)items[i];
        
            item.updateTabText();
        }
        
        layout(true);
    }

	/* (non-Javadoc)
	 * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setVisible(boolean)
	 */
	public void setVisible(boolean visible) {
		super.setVisible(visible);
		getFolder().setVisible(visible);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#showMinMax(boolean)
	 */
	public void showMinMax(boolean show) {
        paneFolder.showMinMax(show);
	}
}
