/*******************************************************************************
 * Copyright (c) 2005, 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.core.commands;

import java.util.Objects;

import org.eclipse.core.commands.common.EventManager;

/**
 * <p>
 * A piece of state information that can be shared between objects, and might be
 * persisted between sessions. This can be used for commands that toggle between
 * two states and wish to pass this state information between different
 * handlers.
 * </p>
 * <p>
 * This state object can either be used as a single state object shared between
 * several commands, or one state object per command -- depending on the needs
 * of the application.
 * </p>
 * <p>
 * Clients may instantiate or extend this class.
 * </p>
 *
 * @since 3.2
 */
public class State extends EventManager {

	/**
	 * The identifier of the state; may be <code>null</code> if it has not
	 * been initialized.
	 */
	private String id;

	/**
	 * The value held by this state; may be anything at all.
	 */
	private Object value;

	/**
	 * Adds a listener to changes for this state.
	 *
	 * @param listener
	 *            The listener to add; must not be <code>null</code>.
	 */
	public void addListener(final IStateListener listener) {
		addListenerObject(listener);
	}

	/**
	 * Disposes of this state. This allows the state to unregister itself with
	 * any managers or as a listener.
	 */
	public void dispose() {
		// The default implementation does nothing.
	}

	/**
	 * Notifies listeners to this state that it has changed in some way.
	 *
	 * @param oldValue
	 *            The old value; may be anything.
	 */
	protected final void fireStateChanged(final Object oldValue) {
		for (Object listener : getListeners()) {
			final IStateListener stateListener = (IStateListener) listener;
			stateListener.handleStateChange(this, oldValue);
		}
	}

	/**
	 * Returns the identifier for this state.
	 *
	 * @return The id; may be <code>null</code>.
	 */
	public final String getId() {
		return id;
	}

	/**
	 * The current value associated with this state. This can be any type of
	 * object, but implementations will usually restrict this value to a
	 * particular type.
	 *
	 * @return The current value; may be anything.
	 */

	public Object getValue() {
		return value;
	}

	/**
	 * Removes a listener to changes from this state.
	 *
	 * @param listener
	 *            The listener to remove; must not be <code>null</code>.
	 */

	public void removeListener(final IStateListener listener) {
		removeListenerObject(listener);
	}

	/**
	 * Sets the identifier for this object.  This method should only be called
	 * by the command framework.  Clients should not call this method.
	 *
	 * @param id
	 *            The id; must not be <code>null</code>.
	 */
	public void setId(final String id) {
		this.id = id;
	}

	/**
	 * Sets the value for this state object.
	 *
	 * @param value
	 *            The value to set; may be anything.
	 */
	public void setValue(final Object value) {
		if (!Objects.equals(this.value, value)) {
			final Object oldValue = this.value;
			this.value = value;
			fireStateChanged(oldValue);
		}
	}
}
