/*******************************************************************************
 * Copyright (c) 2000, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.ui.internal;

import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;

import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.internal.util.PrefUtil;

/**
 * A  {@link ContributionItem} specifically for contributions to the perspective switcher.
 *
 */
public class PerspectiveBarContributionItem extends ContributionItem {

    private IPerspectiveDescriptor perspective;

    private IPreferenceStore apiPreferenceStore = PrefUtil
            .getAPIPreferenceStore();

    private ToolItem toolItem = null;

    private Image image;

    private IWorkbenchPage workbenchPage;

    /**
     * Create a new perspective contribution item
     *
     * @param perspective the descriptor for the perspective
     * @param workbenchPage the page that this perspective is in
     */
    public PerspectiveBarContributionItem(IPerspectiveDescriptor perspective,
            IWorkbenchPage workbenchPage) {
        super(perspective.getId());
        this.perspective = perspective;
        this.workbenchPage = workbenchPage;
    }

    @Override
	public void dispose() {
        super.dispose();
        if (image != null && !image.isDisposed()) {
            image.dispose();
            image = null;
        }
        apiPreferenceStore = null;
        workbenchPage = null;
        perspective = null;

    }

    @Override
	public void fill(ToolBar parent, int index) {
        if (toolItem == null && parent != null && !parent.isDisposed()) {

            if (index >= 0) {
				toolItem = new ToolItem(parent, SWT.CHECK, index);
			} else {
				toolItem = new ToolItem(parent, SWT.CHECK);
			}

            if (image == null || image.isDisposed()) {
                createImage();
            }
            toolItem.setImage(image);

            toolItem.setToolTipText(NLS.bind(WorkbenchMessages.PerspectiveBarContributionItem_toolTip, perspective.getLabel()));
            toolItem.addSelectionListener(widgetSelectedAdapter(event -> select()));
            toolItem.setData(this); //TODO review need for this
            update();
        }
    }

    private void createImage() {
        ImageDescriptor imageDescriptor = perspective.getImageDescriptor();
        if (imageDescriptor != null) {
            image = imageDescriptor.createImage();
        } else {
            image = WorkbenchImages.getImageDescriptor(
                    ISharedImages.IMG_ETOOL_DEF_PERSPECTIVE)
                    .createImage();
        }
    }

    Image getImage() {
        if (image == null) {
            createImage();
        }
        return image;
    }

    /**
     * Select this perspective
     */
    public void select() {
        if (workbenchPage.getPerspective() != perspective) {
            workbenchPage.setPerspective(perspective);
        } else {
			toolItem.setSelection(true);
		}
    }

    @Override
	public void update() {
        if (toolItem != null && !toolItem.isDisposed()) {
            toolItem
                    .setSelection(workbenchPage.getPerspective() == perspective);
            if (apiPreferenceStore
                    .getBoolean(IWorkbenchPreferenceConstants.SHOW_TEXT_ON_PERSPECTIVE_BAR)) {
                if (apiPreferenceStore.getString(
                        IWorkbenchPreferenceConstants.DOCK_PERSPECTIVE_BAR)
                        .equals(IWorkbenchPreferenceConstants.TOP_LEFT)) {
					toolItem.setText(perspective.getLabel());
				} else {
					toolItem.setText(shortenText(perspective.getLabel(),
                            toolItem));
				}
            } else {
                toolItem.setText(""); //$NON-NLS-1$
            }
        }
    }

    /**
     * Update this item with a new perspective descriptor
     * @param newDesc
     */
    public void update(IPerspectiveDescriptor newDesc) {
        perspective = newDesc;
        if (toolItem != null && !toolItem.isDisposed()) {
            ImageDescriptor imageDescriptor = perspective.getImageDescriptor();
            if (imageDescriptor != null) {
                toolItem.setImage(imageDescriptor.createImage());
            } else {
                toolItem.setImage(WorkbenchImages.getImageDescriptor(
                        ISharedImages.IMG_ETOOL_DEF_PERSPECTIVE)
                        .createImage());
            }
            toolItem.setToolTipText(NLS.bind(WorkbenchMessages.PerspectiveBarContributionItem_toolTip, perspective.getLabel() ));
        }
        update();
    }

    IWorkbenchPage getPage() {
        return workbenchPage;
    }

    IPerspectiveDescriptor getPerspective() {
        return perspective;
    }

    ToolItem getToolItem() {
        return toolItem;
    }

    /**
     * Answer whether the receiver is a match for the provided
     * perspective descriptor
     *
     * @param perspective the perspective descriptor
     * @param workbenchPage the page
     * @return <code>true</code> if it is a match
     */
    public boolean handles(IPerspectiveDescriptor perspective,
            IWorkbenchPage workbenchPage) {
        return this.perspective == perspective
                && this.workbenchPage == workbenchPage;
    }

    /**
     * Set the current perspective
     * @param newPerspective
     */
    public void setPerspective(IPerspectiveDescriptor newPerspective) {
        this.perspective = newPerspective;
    }

    // TODO review need for this method
    void setSelection(boolean b) {
        if (toolItem != null && !toolItem.isDisposed()) {
			toolItem.setSelection(b);
		}
    }

    static int getMaxWidth(Image image) {
        return image.getBounds().width * 5;
    }

    private static final String ellipsis = "..."; //$NON-NLS-1$

    protected String shortenText(String textValue, ToolItem item) {
        if (textValue == null || toolItem == null || toolItem.isDisposed()) {
			return null;
		}
        String returnText = textValue;
        GC gc = new GC(item.getParent());
        int maxWidth = getMaxWidth(item.getImage());
        if (gc.textExtent(textValue).x >= maxWidth) {
            for (int i = textValue.length(); i > 0; i--) {
                String test = textValue.substring(0, i);
                test = test + ellipsis;
                if (gc.textExtent(test).x < maxWidth) {
                    returnText = test;
                    break;
                }
            }
        }
        gc.dispose();
        return returnText;
    }
}
