/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef SKY_ENGINE_CORE_DOM_DOCUMENTLIFECYCLE_H_
#define SKY_ENGINE_CORE_DOM_DOCUMENTLIFECYCLE_H_

#include "sky/engine/wtf/Assertions.h"
#include "sky/engine/wtf/Noncopyable.h"

namespace blink {

class DocumentLifecycle {
    WTF_MAKE_NONCOPYABLE(DocumentLifecycle);
public:
    enum State {
        Uninitialized,
        Inactive,

        // When the document is active, it traverses these states.
        VisualUpdatePending,

        InStyleRecalc,
        StyleClean,

        InPreLayout,
        InPerformLayout,
        AfterPerformLayout,
        LayoutClean,

        StyleAndLayoutClean,

        // Once the document starts shuting down, we cannot return
        // to the style/layout/rendering states.
        Stopping,
        Stopped,
        Disposed,
    };

    class Scope {
        WTF_MAKE_NONCOPYABLE(Scope);
    public:
        Scope(DocumentLifecycle&, State finalState);
        ~Scope();

        void setFinalState(State finalState) { m_finalState = finalState; }

    private:
        DocumentLifecycle& m_lifecycle;
        State m_finalState;
    };

    class DeprecatedTransition {
        WTF_MAKE_NONCOPYABLE(DeprecatedTransition);
    public:
        DeprecatedTransition(State from, State to);
        ~DeprecatedTransition();

        State from() const { return m_from; }
        State to() const { return m_to; }

    private:
        DeprecatedTransition* m_previous;
        State m_from;
        State m_to;
    };

    class DetachScope {
        WTF_MAKE_NONCOPYABLE(DetachScope);
    public:
        explicit DetachScope(DocumentLifecycle& documentLifecycle)
            : m_documentLifecycle(documentLifecycle)
        {
            m_documentLifecycle.incrementDetachCount();
        }

        ~DetachScope()
        {
            m_documentLifecycle.decrementDetachCount();
        }

    private:
        DocumentLifecycle& m_documentLifecycle;
    };

    DocumentLifecycle();
    ~DocumentLifecycle();

    bool isActive() const { return m_state > Inactive && m_state < Stopping; }
    State state() const { return m_state; }

    bool stateAllowsTreeMutations() const;
    bool stateAllowsRenderTreeMutations() const;
    bool stateAllowsDetach() const;

    void advanceTo(State);
    void ensureStateAtMost(State);

    void incrementDetachCount() { m_detachCount++; }
    void decrementDetachCount()
    {
        ASSERT(m_detachCount > 0);
        m_detachCount--;
    }

private:
#if ENABLE(ASSERT)
    bool canAdvanceTo(State) const;
    bool canRewindTo(State) const;
#endif

    State m_state;
    int m_detachCount;
};

inline bool DocumentLifecycle::stateAllowsTreeMutations() const
{
    return m_state != InStyleRecalc && m_state != InPerformLayout;
}

inline bool DocumentLifecycle::stateAllowsRenderTreeMutations() const
{
    return m_detachCount || m_state == InStyleRecalc;
}

inline bool DocumentLifecycle::stateAllowsDetach() const
{
    return m_state == VisualUpdatePending
        || m_state == InStyleRecalc
        || m_state == StyleClean
        || m_state == InPreLayout
        || m_state == LayoutClean
        || m_state == StyleAndLayoutClean
        || m_state == Stopping;
}

}

#endif  // SKY_ENGINE_CORE_DOM_DOCUMENTLIFECYCLE_H_
