/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.eclipse.org/org/documents/epl-v10.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.ide.eclipse.adt.internal.editors.layout.gle2;

import static com.android.ide.eclipse.adt.internal.editors.descriptors.TextAttributeDescriptor.DEPRECATED_CATEGORY;

import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.views.properties.IPropertySheetEntry;
import org.eclipse.ui.views.properties.PropertySheetEntry;
import org.eclipse.ui.views.properties.PropertySheetSorter;

/**
 * A customized property sheet page for the graphical layout editor v2.
 * <p/>
 * Currently it just provides a custom tooltip to display attributes javadocs.
 * <p/>
 * The property sheet is linked to the current site's selection service.
 * <p/>
 * Note: this is an exact copy of GLE1's UiPropertySheetPage implementation.
 * The idea is that eventually GLE1 will go away and we'll upgrade this to be
 * a more robust property editor (it currently lacks on so many levels, it's not
 * even worth listing the flaws.)
 *
 * @since GLE2
 */
public class PropertySheetPage extends org.eclipse.ui.views.properties.PropertySheetPage {
    private static final String MISC_CATEGORY = "Misc";

    public PropertySheetPage() {
        super();

        setSorter(new PropertySheetSorter() {
            @Override
            public int compareCategories(String categoryA, String categoryB) {
                // Sort the "Deprecated" category to the bottom, and the "Misc"
                // category second to last.
                if (categoryA.equals(DEPRECATED_CATEGORY)) {
                    return 1;
                } else if (categoryB.equals(DEPRECATED_CATEGORY)) {
                    return -1;
                }
                if (categoryA.equals(MISC_CATEGORY)) {
                    return 1;
                } else if (categoryB.equals(MISC_CATEGORY)) {
                    return -1;
                }

                return super.compareCategories(categoryA, categoryB);
            }
        });
    }

    @Override
    public void createControl(Composite parent) {
        super.createControl(parent);

        setupTooltip();

        // Override parent class' "set status message" behavior. The parent will set
        // the status message to the property's "getDescription()" field. That field
        // may contain newlines, which means the text gets cut off. We want to instead
        // show ALL the text, fit on a single line, and since we don't get to subclass
        // the viewer we will just replace the status message with our own, which works
        // since our mouse listener is registered later so runs later.
        final Tree tree = (Tree) getControl();
        tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseDown(MouseEvent event) {
                Point pt = new Point(event.x, event.y);
                TreeItem item = tree.getItem(pt);
                if (item != null) {
                    Object object = item.getData();
                    if (object instanceof IPropertySheetEntry) {
                        IPropertySheetEntry entry = (IPropertySheetEntry) object;
                        String help = entry.getDescription();
                        if (help != null) {
                            // Strip out newlines to make this a single line entry
                            help = help.replace('\n', ' ');
                            // Remove repeated spaces in case there were trailing spaces
                            help = help.replaceAll("  ", " "); //$NON-NLS-1$ //$NON-NLS-2$
                            IActionBars actionBars = getSite().getActionBars();
                            IStatusLineManager status = actionBars.getStatusLineManager();
                            status.setMessage(help);
                        }
                    }
                }
            }
        });

        // Fix the selection background. In Eclipse 3.5 and 3.6, the selection color
        // is white, painted on top of a white or light blue background (table striping),
        // which is practically unreadable.  This is fixed in 3.7M3, but we need a workaround
        // for earlier releases. This just paints a solid color under the current line in
        // the left column.
        tree.addListener(SWT.EraseItem, new Listener() {
            public void handleEvent(Event event) {
                if ((event.detail & SWT.SELECTED) != 0 && event.index == 0) {
                    GC gc = event.gc;
                    Rectangle rect = event.getBounds();
                    Color background = gc.getBackground();
                    Display display = tree.getDisplay();
                    gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION));
                    gc.fillRectangle(rect.x, rect.y, rect.width, rect.height);
                    gc.setBackground(background);
                }
            }
        });
    }

    /**
     * Sets up a custom tooltip when hovering over tree items.
     * <p/>
     * The tooltip will display the element's javadoc, if any, or the item's getText otherwise.
     */
    private void setupTooltip() {
        final Tree tree = (Tree) getControl();

        /*
         * Reference:
         * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet125.java?view=markup
         */

        final Listener listener = new Listener() {
            Shell tip = null;
            Label label  = null;

            public void handleEvent(Event event) {
                switch(event.type) {
                case SWT.Dispose:
                case SWT.KeyDown:
                case SWT.MouseExit:
                case SWT.MouseDown:
                case SWT.MouseMove:
                    if (tip != null) {
                        tip.dispose();
                        tip = null;
                        label = null;
                    }
                    break;
                case SWT.MouseHover:
                    if (tip != null) {
                        tip.dispose();
                        tip = null;
                        label = null;
                    }

                    String tooltip = null;

                    TreeItem item = tree.getItem(new Point(event.x, event.y));
                    if (item != null) {
                        Object data = item.getData();
                        if (data instanceof PropertySheetEntry) {
                            tooltip = ((PropertySheetEntry) data).getDescription();
                        }

                        if (tooltip == null) {
                            tooltip = item.getText();
                        } else {
                            tooltip = item.getText() + ":\r" + tooltip;
                        }

                        if (tooltip != null) {
                            Shell shell = tree.getShell();
                            Display display = tree.getDisplay();

                            tip = new Shell(shell, SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL);
                            tip.setBackground(display .getSystemColor(SWT.COLOR_INFO_BACKGROUND));
                            FillLayout layout = new FillLayout();
                            layout.marginWidth = 2;
                            tip.setLayout(layout);
                            label = new Label(tip, SWT.NONE);
                            label.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
                            label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
                            label.setData("_TABLEITEM", item);
                            label.setText(tooltip);
                            label.addListener(SWT.MouseExit, this);
                            label.addListener(SWT.MouseDown, this);
                            Point size = tip.computeSize(SWT.DEFAULT, SWT.DEFAULT);
                            Rectangle rect = item.getBounds(0);
                            // Display the tooltip on the same line as the property,
                            // but offset to the right of wherever the mouse cursor was,
                            // such that it does not obscure the list of properties.
                            Point pt = tree.toDisplay(event.x + 15, rect.y);
                            tip.setBounds(pt.x, pt.y, size.x, size.y);
                            tip.setVisible(true);
                        }
                    }
                }
            }
        };

        tree.addListener(SWT.Dispose, listener);
        tree.addListener(SWT.KeyDown, listener);
        tree.addListener(SWT.MouseMove, listener);
        tree.addListener(SWT.MouseHover, listener);

    }

}
