/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package javax.faces.application;

import javax.faces.component.NamingContainer;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.RenderKit;
import javax.faces.render.ResponseStateManager;

import java.io.IOException;


/**
 * <p>
 * <strong class="changed_modified_2_0 changed_modified_2_1 changed_modified_2_2">StateManager</strong>
 * directs the process of saving and
 * restoring the view between requests.  <span class="changed_added_2_0">An
 * implementation
 * of this class must be thread-safe.</span>  The {@link StateManager}
 * instance for an application is retrieved from the {@link Application}
 * instance, and thus cannot know any details of the markup language
 * created by the {@link RenderKit} being used to render a view.  The
 * {@link StateManager} utilizes a helper object ({@link
 * ResponseStateManager}), that is provided by the {@link RenderKit}
 * implementation and is therefore aware of the markup language
 * details.</p>
 */

public abstract class StateManager {

    // ------------------------------------------------------ Manifest Constants


    /**
     * <p>The <code>ServletContext</code> init parameter consulted by
     * the <code>StateManager</code> to tell where the state should be
     * saved.  Valid values are given as the values of the constants:
     * {@link #STATE_SAVING_METHOD_CLIENT} or {@link
     * #STATE_SAVING_METHOD_SERVER}.</p>
     * <p/>
     * <p>If this parameter is not specified, the default value is the
     * value of the constant {@link #STATE_SAVING_METHOD_CLIENT}. </p>
     */
    public static final String STATE_SAVING_METHOD_PARAM_NAME =
          "javax.faces.STATE_SAVING_METHOD";

    /**
     * <p class="changed_added_2_0">The <code>ServletContext</code> init
     * parameter consulted by the runtime to determine if the partial
     * state saving mechanism should be used.</p>

     * <div class="changed_added_2_0">

     * <p>If undefined, the runtime must determine the version level of
     * the application.</p>
     *
     * <ul>

     * <li><p>For applications versioned at 1.2 and under, the runtime
     * must not use the partial state saving mechanism.</li><p>

     * <li><p>For applications versioned at 2.0 and above, the runtime
     * must use the partial state saving mechanism.</p></li>

     * </ul>

     * <p>If this parameter is defined, and the application is versioned
     * at 1.2 and under, the runtime must not use the partial state
     * saving mechanism.  Otherwise, If this param is defined, and
     * calling <code>toLowerCase().equals("true")</code> on a
     * <code>String</code> representation of its value returns
     * <code>true</code>, the runtime must use partial state mechanism.
     * Otherwise the partial state saving mechanism must not be
     * used.</p>

     * </div>
     *
     * @since 2.0
     */
   
    public static final String PARTIAL_STATE_SAVING_PARAM_NAME =
          "javax.faces.PARTIAL_STATE_SAVING";


    /**
     * <p class="changed_added_2_0">The runtime must interpret the value
     * of this parameter as a comma separated list of view IDs, each of
     * which must have their state saved using the state saving
     * mechanism specified in JSF 1.2.</p>
     */
    public static final String FULL_STATE_SAVING_VIEW_IDS_PARAM_NAME =
          "javax.faces.FULL_STATE_SAVING_VIEW_IDS";

    /**
     * <p class="changed_added_2_1">Marker within the
     * <code>FacesContext</code> attributes map to indicate we are
     * saving state.  The implementation must set this marker into the
     * map <b>before</b> starting the state saving traversal and the marker
     * must be cleared, in a finally block, <b>after</b> the traversal is
     * complete.</p>
     */
    public static final String IS_SAVING_STATE =
          "javax.faces.IS_SAVING_STATE";

    /**
     * <p class="changed_added_2_1">Marker within the
     * <code>FacesContext</code> attributes map to indicate we are
     * marking initial state, so the <code>markInitialState()</code>
     * method of iterating components such as {@link
     * javax.faces.component.UIData} could recognize this fact and save
     * the initial state of descendents.</p>

     * @since 2.1

     */
    public final static String IS_BUILDING_INITIAL_STATE =
            "javax.faces.IS_BUILDING_INITIAL_STATE";
    
    /**
     * <p class="changed_added_2_2">
     * If this param is set, and calling toLowerCase().equals("true") on a
     * String representation of its value returns true, and the
     * javax.faces.STATE_SAVING_METHOD is set to "server" (as indicated
     * below), the server state must be guaranteed to be Serializable such
     * that the aggregate state implements java.io.Serializable. The intent
     * of this parameter is to ensure that the act of writing out the state
     * to an ObjectOutputStream would not throw a NotSerializableException,
     * but the runtime is not required verify this before saving the state.      
     * </p>
     * 
     * @since 2.2
     */
        
    public static final String SERIALIZE_SERVER_STATE_PARAM_NAME = 
            "javax.faces.SERIALIZE_SERVER_STATE";

    /**
     * <p>Constant value for the initialization parameter named by
     * the <code>STATE_SAVING_METHOD_PARAM_NAME</code> that indicates
     * state saving should take place on the client.</p>
     */                                   
    public static final String STATE_SAVING_METHOD_CLIENT = "client";


    /**
     * <p>Constant value for the initialization parameter named by
     * the <code>STATE_SAVING_METHOD_PARAM_NAME</code> that indicates
     * state saving should take place on the server.</p>
     */
    public static final String STATE_SAVING_METHOD_SERVER = "server";

    // ---------------------------------------------------- State Saving Methods

    private static final String IS_CALLED_FROM_API_CLASS =
        "javax.faces.ensureOverriddenInvocation";


    /**
     * <p>Return the tree structure and component state information for the
     * view contained in the specified {@link FacesContext} instance as an
     * object of type <code>StateManager.SerializedView</code>.  If there
     * is no state information to be saved, return <code>null</code>
     * instead.</p>
     * <p/>
     * <p>Components may opt out of being included in the serialized view
     * by setting their <code>transient</code> property to <code>true</code>.
     * This must cause the component itself, as well as all of that component's
     * children and facets, to be omitted from the saved  tree structure
     * and component state information.</p>
     * <p/>
     * <p>This method must also enforce the rule that, for components with
     * non-null <code>id</code>s, all components that are descendants of the
     * same nearest {@link NamingContainer} must have unique identifiers.</p>
     *
     * @param context {@link FacesContext} for the current request
      *
     * @throws IllegalStateException if more than one component or
     *                               facet within the same {@link NamingContainer} in this view has
     *                               the same non-<code>null</code> component id
     * @deprecated this has been replaced by {@link #saveView}.  The
     * default implementation calls <code>saveView</code> and inspects the 
     * return.  If the return is an <code>Object []</code>, it casts the
     * result to an <code>Object []</code> wrapping the first and second
     * elements in an instance of {@link SerializedView}, which it then
     * returns.  Otherwise, it returns <code>null</code>
     */
    public SerializedView saveSerializedView(FacesContext context) {

        context.getAttributes().put(IS_CALLED_FROM_API_CLASS, Boolean.TRUE);
        Object stateObj = null;
        try {
            stateObj = saveView(context);
        } finally {
            context.getAttributes().remove(IS_CALLED_FROM_API_CLASS);
        }

        SerializedView result = null;
        if (null != stateObj) {
            if (stateObj instanceof Object[]) {
                Object [] state = (Object[]) stateObj;
                if (state.length == 2) {
                    result = new SerializedView(state[0], state[1]);
                }
            }
        } 
        return result;
    }

    /**
     * <p><span class="changed_deleted_2_2">The functionality of this method
     * is now handled by {@link javax.faces.view.StateManagementStrategy#saveView}.
     * </span> Return an opaque <code>Object</code> containing sufficient
     * information for this same instance to restore the state of the
     * current {@link UIViewRoot} on a subsequent request.  The returned
     * object must implement <code>java.io.Serializable</code>. If there
     * is no state information to be saved, return <code>null</code>
     * instead.</p>
     * <p/>
     * <p>Components may opt out of being included in the serialized view
     * by setting their <code>transient</code> property to <code>true</code>.
     * This must cause the component itself, as well as all of that component's
     * children and facets, to be omitted from the saved  tree structure
     * and component state information.</p>
     * <p/>
     * <p>This method must also enforce the rule that, for components with
     * non-null <code>id</code>s, all components that are descendants of the
     * same nearest {@link NamingContainer} must have unique identifiers.</p>
     * <p/>
     * <p>For backwards compatability with existing
     * <code>StateManager</code> implementations, the default
     * implementation of this method calls {@link #saveSerializedView}
     * and creates and returns a two element <code>Object</code> array
     * with element zero containing the <code>structure</code> property
     * and element one containing the <code>state</code> property of the
     * <code>SerializedView</code>.</p>
     *
     * @param context {@link FacesContext} for the current request
     *
     * @throws IllegalStateException if more than one component or
     *                               facet within the same {@link NamingContainer} in this view has
     *                               the same non-<code>null</code> component id
     * @since 1.2
     */
    @Deprecated
    public Object saveView(FacesContext context) {
        Object stateArray[] = null;

        if (!context.getAttributes().containsKey(IS_CALLED_FROM_API_CLASS)) {
            SerializedView view = saveSerializedView(context);
            if (null != view) {
                stateArray = new Object[]{view.getStructure(),
                            view.getState()};
            }
        }
        return stateArray;
    }


    /**
     * <p>Convenience method, which must be called by
     * <code>saveSerializedView()</code>, to construct and return a
     * <code>Serializable</code> object that represents the structure
     * of the entire component tree (including children and facets)
     * of this view.</p>
     * <p/>
     * <p>Components may opt-out of being included in the tree structure
     * by setting their <code>transient</code> property to <code>true</code>.
     * This must cause the component itself, as well as all of that component's
     * children and facets, to be omitted from the saved  tree structure
     * information.</p>
     *
     * @param context {@link FacesContext} for the current request
     *
     * @deprecated the distinction between tree structure and component
     *             state is now an implementation detail.  The default
     *             implementation returns <code>null</code>.
     */
    protected Object getTreeStructureToSave(FacesContext context) {
        return null;
    }


    /**
     * <p>Convenience method, which must be called by
     * <code>saveSerializedView()</code>, to construct and return a
     * <code>Serializable</code> object that represents the state of
     * all component properties, attributes, and attached objects, for
     * the entire component tree (including children and facets)
     * of this view.</p>
     * <p/>
     * <p>Components may opt-out of being included in the component state
     * by setting their <code>transient</code> property to <code>true</code>.
     * This must cause the component itself, as well as all of that component's
     * children and facets, to be omitted from the saved component state
     * information.</p>
     *
     * @param context {@link FacesContext} for the current request
     *
     * @deprecated the distinction between tree structure and component
     *             state is now an implementation detail.  The default
     *             implementation returns <code>null</code>.
     */
    protected Object getComponentStateToSave(FacesContext context) {
        return null;
    }

    /**
     * <p>Save the state represented in the specified state
     * <code>Object</code> instance, in an implementation dependent
     * manner.</p>
     * <p/>
     * <p>This method will typically simply delegate the actual
     * writing to the <code>writeState()</code> method of the
     * {@link ResponseStateManager} instance provided by the
     * {@link RenderKit} being used to render this view.  This
     * method assumes that the caller has positioned the
     * {@link ResponseWriter} at the correct position for the
     * saved state to be written.</p>
     * <p/>
     * <p>For backwards compatability with existing
     * <code>StateManager</code> implementations, the default
     * implementation of this method checks if the argument is an
     * instance of <code>Object []</code> of length greater than or
     * equal to two.  If so, it creates a <code>SerializedView</code>
     * instance with the tree structure coming from element zero and
     * the component state coming from element one and calls through to
     * {@link
     * #writeState(javax.faces.context.FacesContext,javax.faces.application.StateManager.SerializedView)}.
     * If not, does nothing.</p>
     *
     * @param context {@link FacesContext} for the current request
     * @param state   the Serializable state to be written,
     *                as returned by {@link #saveSerializedView}
     *
     * @since 1.2
     */
    public void writeState(FacesContext context, Object state)
          throws IOException {
        if (null != state && state.getClass().isArray() &&
            state.getClass().getComponentType().equals(Object.class)) {
            Object stateArray[] = (Object[]) state;
            if (2 == stateArray.length) {
                SerializedView view = new SerializedView(stateArray[0],
                                                         stateArray[1]);
                writeState(context, view);
            }
        }
    }

    /**
     * <p>Save the state represented in the specified
     * <code>SerializedView</code> isntance, in an implementation
     * dependent manner.</p>
     * <p/>
     * <p>This method must consult the context initialization parameter
     * named by the symbolic constant
     * <code>StateManager.STATE_SAVING_METHOD_PARAM_NAME</code>
     * to determine whether state should be saved on the client or the
     * server.  If not present, client side state saving is assumed.</p>
     * <p/>
     * <p>If the init parameter indicates that client side state
     * saving should be used, this method must delegate the actual
     * writing to the <code>writeState()</code> method of the
     * {@link ResponseStateManager} instance provided by the
     * {@link RenderKit} being used to render this view.  This
     * method assumes that the caller has positioned the
     * {@link ResponseWriter} at the correct position for the
     * saved state to be written.</p>
     *
     * @param context {@link FacesContext} for the current request
     * @param state   the serialized state to be written
     *
     * @deprecated This method has been replaced by {@link
     *             #writeState(javax.faces.context.FacesContext,java.lang.Object)}.
     *             The default implementation calls the non-deprecated variant
     * of the method passing an <code>Object []</code> as the second
     * argument, where the first element of the array is the return from
     * <code>getStructure()</code> and the second is the return from
     * <code>getState()</code> on the argument <code>state</code>.
     * 
     */
    public void writeState(FacesContext context,
                           SerializedView state) throws IOException {

        if (state != null) {
            writeState(context, new Object[]{state.getStructure(),
                                             state.getState()});
        }
        
    }

    // ------------------------------------------------- State Restoring Methods


    /**
     * <p><span class="changed_deleted_2_2">The functionality of this method
     * is now handled by {@link javax.faces.view.StateManagementStrategy#restoreView}.
     * </span> Restore the tree structure and the component state of the view
     * for the specified <code>viewId</code>, in an implementation dependent
     * manner, and return the restored {@link UIViewRoot}.  If there is no
     * saved state information available for this <code>viewId</code>,
     * return <code>null</code> instead.</p>
     * <p/>
     * <p>This method must consult the context initialization parameter
     * named by the symbolic constant
     * <code>StateManager.STATE_SAVING_METHOD_PARAM_NAME</code>
     * to determine whether state should be saved on the client or the
     * server.  If not present, client side state saving is assumed.</p>
     * <p/>
     * <p>If the init parameter indicates that client side state
     * saving should be used, this method must call the
     * <code>getTreeStructureToRestore()</code> and (if the previous method
     * call returned a non-null value) <code>getComponentStateToRestore()</code>
     * methods of the {@link ResponseStateManager} instance provided by the
     * {@link RenderKit} responsible for this view.</p>
     *
     * @param context     {@link FacesContext} for the current request
     * @param viewId      View identifier of the view to be restored
     * @param renderKitId the renderKitId used to render this response.
     *                    Must not be <code>null</code>.
     *
     * @throws IllegalArgumentException if <code>renderKitId</code>
     *                                  is <code>null</code>.
     */
    @Deprecated
    public abstract UIViewRoot restoreView(FacesContext context, String viewId,
                                           String renderKitId);


    /**
     * <p>Convenience method, which must be called by
     * <code>restoreView()</code>, to construct and return a {@link UIViewRoot}
     * instance (populated with children and facets) representing the
     * tree structure of the component tree being restored.  If no saved
     * state information is available, return <code>null</code> instead.</p>
     *
     * @param context     {@link FacesContext} for the current request
     * @param viewId      View identifier of the view to be restored
     * @param renderKitId the renderKitId used to render this response.
     *                    Must not be <code>null</code>.
     *
     * @throws IllegalArgumentException if <code>renderKitId</code>
     *                                  is <code>null</code>.
     * @deprecated the distinction between tree structure and component
     *             state is now an implementation detail.  The default
     *             implementation returns <code>null</code>.
     */
    protected UIViewRoot restoreTreeStructure(FacesContext context,
                                              String viewId,
                                              String renderKitId) {
        return null;
    }


    /**
     * <p>Convenience method, which must be called by
     * <code>restoreView()</code>, to restore the attributes, properties,
     * and attached objects of all components in the restored component tree.
     * </p>
     *
     * @param context     {@link FacesContext} for the current request
     * @param viewRoot    {@link UIViewRoot} returned by a previous call
     *                    to <code>restoreTreeStructure()</code>
     * @param renderKitId the renderKitId used to render this response.
     *                    Must not be <code>null</code>.
     *
     * @throws IllegalArgumentException if <code>renderKitId</code>
     *                                  is <code>null</code>.
     * @deprecated the distinction between tree structure and component
     *             state is now an implementation detail.  The default
     *             implementation does nothing.
     */
    protected void restoreComponentState(FacesContext context,
                                         UIViewRoot viewRoot,
                                         String renderKitId) {
    }


    private Boolean savingStateInClient = null;

    /**
     * @return <code>true</code> if and only if the value of the
     *         <code>ServletContext</code> init parameter named by the value of
     *         the constant {@link #STATE_SAVING_METHOD_PARAM_NAME} is equal to
     *         the value of the constant {@link #STATE_SAVING_METHOD_CLIENT}.
     *         <code>false</code> otherwise.
     *
     * @throws NullPointerException if <code>context</code> is
     *                              <code>null</code>.
     */

    public boolean isSavingStateInClient(FacesContext context) {
        if (null != savingStateInClient) {
            return savingStateInClient.booleanValue();
        }
        savingStateInClient = Boolean.FALSE;

        String saveStateParam = context.getExternalContext().
              getInitParameter(STATE_SAVING_METHOD_PARAM_NAME);
        if (saveStateParam != null &&
            saveStateParam.equalsIgnoreCase(STATE_SAVING_METHOD_CLIENT)) {
            savingStateInClient = Boolean.TRUE;
        }
        return savingStateInClient.booleanValue();
    }

    /**
     * <p>Convenience struct for encapsulating tree structure and
     * component state.  This is necessary to allow the API to be
     * flexible enough to work in JSP and non-JSP environments.</p>
     *
     * @deprecated This class was not marked <code>Serializable</code>
     *             in the 1.0 version of the spec.  It was also not a static inner
     *             class, so it can't be made to be <code>Serializable</code>.
     *             Therefore, it is being deprecated in version 1.2 of the spec.
     *             The replacement is to use an implementation dependent
     *             <code>Object</code>.
     */

    public class SerializedView extends Object {
        private Object structure = null;
        private Object state = null;

        public SerializedView(Object newStructure, Object newState) {
            structure = newStructure;
            state = newState;
        }

        public Object getStructure() {
            return structure;
        }

        public Object getState() {
            return state;
        }
    }

    /**
     * <p class="changed_added_2_0">
     * Convenience method to return the view state as a <code>String</code> with
     * no <code>RenderKit</code> specific markup.
     *
     * This default implementation of this method will call {@link #saveView(javax.faces.context.FacesContext)}
     * and passing the result to and returning the resulting value from
     * {@link ResponseStateManager#getViewState(javax.faces.context.FacesContext, Object)}.
     * </p>
     *
     * @param context {@link FacesContext} for the current request
     *
     * @since 2.0
     */
    public String getViewState(FacesContext context) {
        Object state = saveView(context);
        return context.getRenderKit().getResponseStateManager().getViewState(context, state);
    }
}
