/*******************************************************************************
 * Copyright (c) 2004, 2005 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
 *******************************************************************************/
package org.eclipse.ui.internal.presentations.defaultpresentation;

import org.eclipse.jface.util.Geometry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabFolder2Adapter;
import org.eclipse.swt.custom.CTabFolderEvent;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.ViewForm;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Cursor;
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.Listener;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IPropertyListener;
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.layout.CellLayout;
import org.eclipse.ui.internal.layout.LayoutUtil;
import org.eclipse.ui.internal.layout.Row;
import org.eclipse.ui.internal.layout.SizeCache;
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.ProxyControl;
import org.eclipse.ui.internal.presentations.util.TabFolderEvent;
import org.eclipse.ui.internal.util.Util;

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

    private Composite control;
    private CTabFolder folder;
    private Control viewToolBar;
    private ViewForm viewForm;
    private ProxyControl toolbarProxy;
    private Composite topLeftControl;
    private SizeCache toolbarCache;
    private Cursor dragCursor;
    
    private static final String FULL_TITLE = "part_title"; //$NON-NLS-1$
    
    // CTabFolder listener
    private CTabFolder2Adapter expandListener = new CTabFolder2Adapter() {
        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.swt.custom.CTabFolder2Adapter#close(org.eclipse.swt.custom.CTabFolderEvent)
         */
        public void close(CTabFolderEvent event) {
            event.doit = false;
            fireEvent(TabFolderEvent.EVENT_CLOSE, getTab(event.item));
        }

        public void showList(CTabFolderEvent event) {
            event.doit = false;
            fireEvent(TabFolderEvent.EVENT_SHOW_LIST);
        }

    };
    
    
    private Listener selectionListener = new Listener() {
        public void handleEvent(Event e) {
            fireEvent(TabFolderEvent.EVENT_TAB_SELECTED, getTab(e.item));
        }
    };
    
    private IPropertyListener systemToolbarListener = new IPropertyListener() {

        public void propertyChanged(Object source, int propId) {
            Point location;
            
            if (propId == TabFolderEvent.EVENT_PANE_MENU) {
                location = getPaneMenuLocation();
            } else {
                location = new Point(0,0);
            }
            
            fireEvent(propId, getSelection(), location);
        }
        
    };

    private DisposeListener tabDisposeListener = new DisposeListener() {
        public void widgetDisposed(DisposeEvent e)
        {
            if (e.widget == control) {
                disposed();
            }
        }  
    };
    
    public DetachedViewTabFolder(Composite parent) {
        control = new Composite(parent, SWT.NONE);
        control.addDisposeListener(tabDisposeListener);
        CellLayout layout = new CellLayout(1)
            .setDefaultRow(Row.fixed())
            .setDefaultColumn(Row.growing())
            .setRow(0, Row.growing())
            .setSpacing(0, 0)
            .setMargins(0, 0);
        control.setLayout(layout);
        dragCursor = parent.getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL);
        
        viewForm = new ViewForm(control, SWT.FLAT);
        attachListeners(viewForm, false);
        
        topLeftControl = new Composite(viewForm, SWT.NONE);
        topLeftControl.setLayout(new CellLayout(0).setDefaultColumn(Row.fixed()).setSpacing(0,0).setMargins(0,0));
        topLeftControl.setCursor(dragCursor);
        attachListeners(topLeftControl, false);
        toolbarProxy = new ProxyControl(topLeftControl);
        viewForm.setTopLeft(topLeftControl);
       
        toolbarCache = new SizeCache();
        
        folder = new CTabFolder(control, SWT.BOTTOM);
        folder.setMinimizeVisible(false);
        folder.setMaximizeVisible(false);
        folder.setUnselectedCloseVisible(true);
        folder.setUnselectedImageVisible(true);
        folder.addListener(SWT.Selection, selectionListener);
        folder.addCTabFolder2Listener(expandListener);
        attachListeners(folder, false);
        
        // Initialize view menu dropdown
        {            
            ToolBar actualToolBar = new ToolBar(viewForm, SWT.FLAT | SWT.NO_BACKGROUND);
            viewToolBar = actualToolBar;
            
            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.Menu); 
            actualToolBar.addMouseListener(new MouseAdapter() {
                public void mouseDown(MouseEvent e) {
                    fireEvent(TabFolderEvent.EVENT_PANE_MENU, getSelection(), getPaneMenuLocation());
                }
            });
        }
        
        viewForm.setTopRight(viewToolBar);
    }

    protected void disposed() {

    }

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

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#add(int)
     */
    public AbstractTabItem add(int index, int flags) {
        DetachedViewTabItem item = new DetachedViewTabItem(this, index, flags);
        item.getWidget().setData(item);
        item.getWidget().addDisposeListener(tabDisposeListener);
        
        if (folder.getItemCount() == 2) {
            layout(true);
        }
        
        return item;
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#layout(boolean)
     */
    public void layout(boolean flushCache) {
        
        Rectangle oldBounds = viewForm.getBounds();
        
        CellLayout layout = (CellLayout)control.getLayout();
        if (folder.getItemCount() < 2) {
            layout.setRow(1, Row.fixed(0));
        } else {
            layout.setRow(1, Row.fixed(folder.getTabHeight() + 2));
        }
        
        super.layout(flushCache);
        
        control.layout(flushCache);
        
        Rectangle newBounds = viewForm.getBounds();
        
        if (Util.equals(oldBounds, newBounds)) {
            viewForm.layout(flushCache);
        }
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getClientArea()
     */
    public Rectangle getClientArea() {
        Control content = viewForm.getContent();
        
        if (content == null) {
            return new Rectangle(0,0,0,0);
        }
        
        return Geometry.toControl(control, DragUtil.getDisplayBounds(content));
    }

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

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setSelection(org.eclipse.ui.internal.presentations.util.Widget)
     */
    public void setSelection(AbstractTabItem toSelect) {
        if (toSelect == null) {
            return;
        }
        
        DetachedViewTabItem tab = (DetachedViewTabItem) toSelect;
        folder.setSelection((CTabItem)tab.getWidget());
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setSelectedInfo(org.eclipse.ui.internal.presentations.util.PartInfo)
     */
    public void setSelectedInfo(PartInfo info) {
    }
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getToolbarParent()
     */
    public Composite getToolbarParent() {
        return viewForm;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getTabArea()
     */
    public Rectangle getTabArea() {
        return Geometry.toDisplay(folder.getParent(), folder.getBounds());
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setToolbar(org.eclipse.swt.widgets.Control)
     */
    public void setToolbar(Control toolbarControl) {
        
        if (toolbarControl == getToolbar()) {
            return;
        }
        
        if (toolbarControl != null) {
            toolbarCache.setControl(toolbarControl);
            toolbarProxy.setTarget(toolbarCache);
            toolbarProxy.getControl().getParent().changed(new Control[]{toolbarProxy.getControl()});
            LayoutUtil.resize(toolbarProxy.getControl());

            toolbarProxy.layout();

        } else {
            toolbarCache.setControl(null);
            toolbarProxy.setTarget(null);
        }
        
        super.setToolbar(toolbarControl);
    }
    
    public Control getControl() {
        return control;
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#isOnBorder(org.eclipse.swt.graphics.Point)
     */
    public boolean isOnBorder(Point globalPos) {
        Point localPos = getControl().toControl(globalPos);
        
        Rectangle clientArea = getClientArea();
        return localPos.y > clientArea.y && localPos.y < clientArea.y + clientArea.height; 
    }
    
    public AbstractTabItem getSelection() {
        CTabItem sel = folder.getSelection();
        
        if (sel == null) {
            return null;
        }
        
        return getTab(sel);
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#getContentParent()
     */
    public Composite getContentParent() {
        return viewForm;
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.presentations.util.AbstractTabFolder#setContent(org.eclipse.swt.widgets.Control)
     */
    public void setContent(Control newContent) {
        viewForm.setContent(newContent);
    }
    
    /**
     * @return
     * @since 3.1
     */
    public CTabFolder getTabFolder() {
        return folder;
    }
    
    protected void handleDragStarted(Point displayPos, Event e) {
        if (isOnBorder(displayPos)) {
            return;
        }
        
        AbstractTabItem tab = null;
        
        if (DragUtil.getDisplayBounds(viewForm).contains(displayPos)) {
            tab = getSelection();
        } else {
            tab = getItem(displayPos); 
        }
        
        fireEvent(TabFolderEvent.EVENT_DRAG_START, tab, displayPos);
    }

    public Point getPartListLocation() {

        // get the last visible item
        int numItems = folder.getItemCount();
        CTabItem item = null, tempItem = null;
        for (int i = 0; i < numItems; i++) {
            tempItem = folder.getItem(i);
            if (tempItem.isShowing())
                item = tempItem;
        }

        // if we have no visible tabs, abort.
        if (item == null)
            return new Point(0, 0);

        Rectangle itemBounds = item.getBounds();
        int x = itemBounds.x + itemBounds.width;
        int y = itemBounds.y + itemBounds.height;
        return folder.toDisplay(new Point(x, y));
    }
    
    public Point getPaneMenuLocation() {
        Point toolbarSize = viewToolBar.getSize();
        
        return viewToolBar.toDisplay(0,toolbarSize.y);
    }
    
    public void enablePaneMenu(boolean enabled) {
        if (enabled) {
            viewToolBar.setVisible(true);
        } else {
            viewToolBar.setVisible(false);
        }
    }

    public void itemRemoved() {
        if (folder.getItemCount() == 1 && !control.isDisposed() && !viewForm.isDisposed()) {
            layout(true);
        }
    }

}
