/*******************************************************************************
 * 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 org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IElementFactory;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPersistableElement;
import org.eclipse.ui.PlatformUI;

/**
 * An item in the editor history.
 */
public class EditorHistoryItem {

    private IEditorInput input;

    private IEditorDescriptor descriptor;

    private IMemento memento;

    /**
     * Constructs a new item.
     */
    public EditorHistoryItem(IEditorInput input, IEditorDescriptor descriptor) {
        this.input = input;
        this.descriptor = descriptor;
    }

    /**
     * Constructs a new item from a memento.
     */
    public EditorHistoryItem(IMemento memento) {
        this.memento = memento;
    }

    /**
     * Returns the editor descriptor.
     *
     * @return the editor descriptor.
     */
    public IEditorDescriptor getDescriptor() {
        return descriptor;
    }

    /**
     * Returns the editor input.
     *
     * @return the editor input.
     */
    public IEditorInput getInput() {
        return input;
    }

    /**
     * Returns whether this item has been restored from the memento.
     */
    public boolean isRestored() {
        return memento == null;
    }

    /**
     * Returns the name of this item, either from the input if restored,
     * otherwise from the memento.
     */
    public String getName() {
        if (isRestored() && getInput() != null) {
            return getInput().getName();
        } else if (memento != null) {
            String name = memento.getString(IWorkbenchConstants.TAG_NAME);
            if (name != null) {
                return name;
            }
        }
        return ""; //$NON-NLS-1$
    }

    /**
     * Returns the tooltip text of this item, either from the input if restored,
     * otherwise from the memento.
     */
    public String getToolTipText() {
        if (isRestored() && getInput() != null) {
            return getInput().getToolTipText();
        } else if (memento != null) {
            String name = memento.getString(IWorkbenchConstants.TAG_TOOLTIP);
            if (name != null) {
                return name;
            }
        }
        return ""; //$NON-NLS-1$
    }

    /**
     * Returns whether this item matches the given editor input.
     */
    public boolean matches(IEditorInput input) {
        if (isRestored()) {
			return input.equals(getInput());
		}
        // if not restored, compare name, tool tip text and factory id,
        // avoiding as much work as possible
        if (!getName().equals(input.getName())) {
			return false;
		}
        if (!getToolTipText().equals(input.getToolTipText())) {
			return false;
		}
        IPersistableElement persistable = input.getPersistable();
        String inputId = persistable == null ? null : persistable
                .getFactoryId();
        String myId = getFactoryId();
        return myId == null ? inputId == null : myId.equals(inputId);
    }

    /**
     * Returns the factory id of this item, either from the input if restored,
     * otherwise from the memento.
     * Returns <code>null</code> if there is no factory id.
     */
    public String getFactoryId() {
        if (isRestored()) {
            if (input != null) {
                IPersistableElement persistable = input.getPersistable();
                if (persistable != null) {
                    return persistable.getFactoryId();
                }
            }
        } else if (memento != null) {
            return memento.getString(IWorkbenchConstants.TAG_FACTORY_ID);
        }
        return null;
    }

    /**
     * Restores the object state from the memento.
     */
    public IStatus restoreState() {
        Assert.isTrue(!isRestored());

        IStatus result = Status.OK_STATUS;
        IMemento memento = this.memento;
        this.memento = null;

        String factoryId = memento
                .getString(IWorkbenchConstants.TAG_FACTORY_ID);
        if (factoryId == null) {
            WorkbenchPlugin
                    .log("Unable to restore mru list - no input factory ID.");//$NON-NLS-1$
            return result;
        }
        IElementFactory factory = PlatformUI.getWorkbench().getElementFactory(
                factoryId);
        if (factory == null) {
            return result;
        }
        IMemento persistableMemento = memento
                .getChild(IWorkbenchConstants.TAG_PERSISTABLE);
        if (persistableMemento == null) {
            WorkbenchPlugin
                    .log("Unable to restore mru list - no input element state: " + factoryId);//$NON-NLS-1$
            return result;
        }
        IAdaptable adaptable = factory.createElement(persistableMemento);
        if (adaptable == null || (adaptable instanceof IEditorInput) == false) {
            return result;
        }
        input = (IEditorInput) adaptable;
        // Get the editor descriptor.
        String editorId = memento.getString(IWorkbenchConstants.TAG_ID);
        if (editorId != null) {
            IEditorRegistry registry = WorkbenchPlugin.getDefault()
                    .getEditorRegistry();
            descriptor = registry.findEditor(editorId);
        }
        return result;
    }

    /**
     * Returns whether this history item can be saved.
     */
    public boolean canSave() {
        return !isRestored()
                || (getInput() != null && getInput().getPersistable() != null);
    }

    /**
     * Saves the object state in the given memento.
     *
     * @param memento the memento to save the object state in
     */
    public IStatus saveState(IMemento memento) {
        if (!isRestored()) {
            memento.putMemento(this.memento);
        } else if (input != null) {

            IPersistableElement persistable = input.getPersistable();
            if (persistable != null) {
                /*
                 * Store IPersistable of the IEditorInput in a separate section
                 * since it could potentially use a tag already used in the parent
                 * memento and thus overwrite data.
                 */
                IMemento persistableMemento = memento
                        .createChild(IWorkbenchConstants.TAG_PERSISTABLE);
                persistable.saveState(persistableMemento);
                memento.putString(IWorkbenchConstants.TAG_FACTORY_ID,
                        persistable.getFactoryId());
                if (descriptor != null && descriptor.getId() != null) {
                    memento.putString(IWorkbenchConstants.TAG_ID, descriptor
                            .getId());
                }
                // save the name and tooltip separately so they can be restored
                // without having to instantiate the input, which can activate plugins
                memento
                        .putString(IWorkbenchConstants.TAG_NAME, input
                                .getName());
                memento.putString(IWorkbenchConstants.TAG_TOOLTIP, input
                        .getToolTipText());
            }
        }
        return Status.OK_STATUS;
    }

}
