/*******************************************************************************
 * 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.part;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.components.framework.IDisposable;
import org.eclipse.ui.internal.part.components.services.IDirtyHandler;
import org.eclipse.ui.internal.part.components.services.IInputHandler;
import org.eclipse.ui.internal.part.components.services.INameable;
import org.eclipse.ui.internal.part.components.services.IPartDescriptor;
import org.eclipse.ui.internal.util.Util;

/**
 * Note: this class is used in an addInstance call -- if this class implements an
 * interface, that interface will override anything that the object had in its local
 * context.
 * 
 * @since 3.1
 */
public class PartPropertyProvider implements IPartPropertyProvider, INameable, IDirtyHandler, IDisposable, IInputHandler {

    // Dependencies
    private INameable nameable;
    private IDirtyHandler dirty;
    private List listeners = new ArrayList();   
    
    private String tooltip = ""; //$NON-NLS-1$
    private String partName;
    private String contentDescription = ""; //$NON-NLS-1$
    private String title = ""; //$NON-NLS-1$
    private boolean isDirty = false;
    private ImageDescriptor titleImage;
    private Image image = null;
    private IEditorInput input;
    private ResourceManager mgr;
    
    private final static class ListenerRec {
        public ListenerRec(IPropertyListener l, IWorkbenchPart p) {
            this.l = l;
            this.part = p;
        }
        
        public boolean equals(Object other) {
            if (!(other instanceof ListenerRec)) return false;
            
            ListenerRec lr = (ListenerRec)other;
            return (lr.l == l) && (lr.part == part);
        }
        
        public IPropertyListener l;
        public IWorkbenchPart part;
    };
    
    public PartPropertyProvider(ResourceManager manager, INameable parentNameable, 
            IDirtyHandler dirtyListener, IPartDescriptor descriptor, IEditorInput initialInput) {
        this.nameable = parentNameable;
        this.dirty = dirtyListener;
        this.partName = descriptor.getLabel();
        this.titleImage = descriptor.getImage();
        this.input = initialInput;
        this.mgr = manager;
    }
    
    private ResourceManager getManager() {
        if (mgr == null) {
            mgr = JFaceResources.getResources();
        }
        return mgr;
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.IPartPropertyProvider#addPropertyListener(org.eclipse.ui.IWorkbenchPart, org.eclipse.ui.IPropertyListener)
     */
    public void addPropertyListener(IWorkbenchPart part, IPropertyListener l) {
        listeners.add(new ListenerRec(l, part));
    }

    public void removePropertyListener(IWorkbenchPart part, IPropertyListener l) {
        listeners.remove(new ListenerRec(l, part));
    }
        
    /**
     * @return Returns the title.
     */
    public String getTitle() {
        return title;
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.IPartPropertyProvider#getTitleToolTip()
     */
    public String getTitleToolTip() {
        return tooltip;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.IPartPropertyProvider#getTitleImage()
     */
    public Image getTitleImage() {
        if (image == null) {
            if (titleImage == null) {
                return PlatformUI.getWorkbench().getSharedImages().getImage(
                        ISharedImages.IMG_DEF_VIEW);
            }
            
            image = getManager().createImageWithDefault(titleImage);
        }
        
        return image;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.IPartPropertyProvider#getPartName()
     */
    public String getPartName() {
        return partName;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.IPartPropertyProvider#getContentDescription()
     */
    public String getContentDescription() {
        return contentDescription;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.IPartPropertyProvider#getEditorInput()
     */
    public IEditorInput getEditorInput() {
        return input;
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.IPartPropertyProvider#isDirty()
     */
    public boolean isDirty() {
        return isDirty;
    }

    /* (non-Javadoc)
     * @see org.eclipse.core.component.IDisposable#dispose()
     */
    public void dispose() {
        listeners.clear();
        
        if (image != null) {
            getManager().destroy(titleImage);
        }
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.components.services.INameable#setContentDescription(java.lang.String)
     */
    public void setContentDescription(String contentDescription) {
        if (this.contentDescription.equals(contentDescription)) {
            return;
        }
        
        this.contentDescription = contentDescription;
        
        if (nameable != null) {
            nameable.setContentDescription(contentDescription);
        }
        
        firePropertyChange(IWorkbenchPartConstants.PROP_CONTENT_DESCRIPTION);
    }
    
    public void setDirty(boolean isDirty) {
        if (isDirty == this.isDirty) {
            return;
        }
        
        this.isDirty = isDirty;
        
        if (dirty != null) {
            dirty.setDirty(isDirty);
        }
        
        firePropertyChange(IWorkbenchPartConstants.PROP_DIRTY);
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.components.services.INameable#setImage(org.eclipse.jface.resource.ImageDescriptor)
     */
    public void setImage(ImageDescriptor theImage) {
        ImageDescriptor oldImageDescriptor = this.titleImage;
        Image oldImage = image;
        
        if (oldImageDescriptor == theImage) {
            return;
        }
        
        this.titleImage = theImage;
        this.image = null;
        
        if (nameable != null) {
            nameable.setImage(theImage);
        }
        
        firePropertyChange(IWorkbenchPartConstants.PROP_TITLE);
        
        if (oldImage != null) {
            getManager().destroy(oldImageDescriptor);
        }
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.components.services.INameable#setName(java.lang.String)
     */
    public void setName(String newName) {
        if (this.partName.equals(newName)) {
            return;
        }
        
        this.partName = newName;
        
        if (nameable != null) {
            nameable.setName(newName);
        }
        
        firePropertyChange(IWorkbenchPartConstants.PROP_PART_NAME);
        
        setDefaultTitle();
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.ui.internal.part.components.services.INameable#setTooltip(java.lang.String)
     */
    public void setTooltip(String toolTip) {
        if (this.tooltip.equals(toolTip)) {
            return;
        }
        
        this.tooltip = toolTip;
        
        if (nameable != null) {
            nameable.setTooltip(toolTip);
        }
        
        firePropertyChange(IWorkbenchPartConstants.PROP_TITLE);
    }

    /**
     * @param input The input to set.
     */
    public void setEditorInput(IEditorInput input) {
        if (this.input.equals(input)) {
            return;   
        }
        
        this.input = input;
        
        firePropertyChange(IWorkbenchPartConstants.PROP_INPUT);
    }

    private void setTitle(String newTitle) {
        if (newTitle.equals(this.title)) {
            return;
        }
        
        this.title = newTitle;
        firePropertyChange(IWorkbenchPartConstants.PROP_TITLE);
    }
    
    void setDefaultTitle() {
        String description = getContentDescription();
        String name = getPartName();
        String newTitle = name;

        if (!Util.equals(description, "")) { //$NON-NLS-1$
            newTitle = MessageFormat
                    .format(
                            WorkbenchMessages.WorkbenchPart_AutoTitleFormat, new String[] { name, description });
        }

        setTitle(newTitle);
    }
    
    /**
     * Fires a property changed event.
     *
     * @param propertyId the id of the property that changed
     */
    protected void firePropertyChange(final int propertyId) {
        for (Iterator iter = listeners.iterator(); iter.hasNext();) {
            final ListenerRec rec = (ListenerRec) iter.next();

            Platform.run(new SafeRunnable() {
                public void run() {
                    rec.l.propertyChanged(rec.part, propertyId);
                }
            });
        }        
    }
}
