/*
 * Copyright (C) The Apache Software Foundation. All rights reserved.
 *
 * This software is published under the terms of the Apache Software License
 * version 1.1, a copy of which has been included with this distribution in
 * the LICENSE file.
 */
 package org.apache.avalon.framework;

/**
 * This class provides basic facilities for enforcing Avalon's contracts
 * within your own code.
 *
 * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
 * @version CVS $Revision: 1.2 $ $Date: 2001/11/19 17:50:20 $
 */
public final class ComponentStateValidator
{
    private static final long LOG_ENABLED    = 0x00000001;
    private static final long CONTEXTUALIZED = 0x00000002;
    private static final long PARAMETERIZED  = 0x00000004;
    private static final long CONFIGURED     = 0x00000008;
    private static final long COMPOSED       = 0x00000010;
    private static final long ACTIVE         = 0x10000000;
    private static final long INITIALIZED    = 0x00000012;
    private static final long STARTED        = 0x00000014;
    private static final long SUSPENDED      = 0x01000000;
    private static final long STOPPED        = 0x00000018;
    private static final long DISPOSED       = 0x00000020;
    private static final long INIT_MASK      = LOG_ENABLED | CONTEXTUALIZED
                                              | PARAMETERIZED | CONFIGURED
                                              | COMPOSED | INITIALIZED
                                              | STARTED;
    private long mask;
    private long state;

    /**
     * Create state validator from object (this can be used for more than just
     * components).
     */
    public ComponentStateValidator( Object obj )
    {
        if ( obj instanceof org.apache.avalon.framework.logger.LogEnabled ||
             obj instanceof org.apache.avalon.framework.logger.Loggable )
        {
            this.mask |= LOG_ENABLED;
        }

        if ( obj instanceof org.apache.avalon.framework.context.Contextualizable )
        {
            this.mask |= CONTEXTUALIZED;
        }

        if ( obj instanceof org.apache.avalon.framework.parameters.Parameterizable )
        {
            this.mask |= PARAMETERIZED;
        }

        if ( obj instanceof org.apache.avalon.framework.configuration.Configurable )
        {
            this.mask |= CONFIGURED;
        }

        if ( obj instanceof org.apache.avalon.framework.component.Composable )
        {
            this.mask |= COMPOSED;
        }

        if ( obj instanceof org.apache.avalon.framework.activity.Initializable )
        {
            this.mask |= INITIALIZED;
        }

        if ( obj instanceof org.apache.avalon.framework.activity.Disposable )
        {
            this.mask |= DISPOSED;
        }

        if ( obj instanceof org.apache.avalon.framework.activity.Startable )
        {
            this.mask |= STARTED | STOPPED;
        }

        if ( obj instanceof org.apache.avalon.framework.activity.Suspendable )
        {
            this.mask |= SUSPENDED;
        }

        this.state = this.mask & ~ACTIVE;
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the LOG_ENABLED state has already been set, if the component implements
     * LogEnabled or Logger, and if the state has progressed beyond the Logger
     * stage.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkLogEnabled( final String message )
    {
        if ( ( (this.state & this.mask & LOG_ENABLED) > 0 ) || ( (this.mask & LOG_ENABLED) == 0 ) || ( this.state > LOG_ENABLED ) )
        {
            throw new IllegalStateException( message );
        }

        this.state |= LOG_ENABLED;
        if ( (this.state & INIT_MASK) == (this.mask & INIT_MASK) )
        {
            this.state |= ACTIVE;
        }
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the CONTEXTUALIZED state has already been set, if the component implements
     * Contextualizable, and if the state has progressed beyond the Context stage.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkContextualized( final String message )
    {
        if ( ( (this.state & this.mask & CONTEXTUALIZED) > 0 ) || ( (this.mask & CONTEXTUALIZED) == 0 ) || ( this.state > CONTEXTUALIZED ) )
        {
            throw new IllegalStateException( message );
        }

        this.state |= CONTEXTUALIZED;
        if ( (this.state & INIT_MASK) == (this.mask & INIT_MASK) )
        {
            this.state |= ACTIVE;
        }
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the PARAMETERIZED state has already been set, if the component implements
     * Parameterizable, and if the state has progressed beyond the Parameters stage.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkParameterized( final String message )
    {
        if ( ( (this.state & this.mask & PARAMETERIZED) > 0 ) || ( (this.mask & PARAMETERIZED) == 0 ) || ( this.state > PARAMETERIZED ) )
        {
            throw new IllegalStateException( message );
        }

        this.state |= PARAMETERIZED;
        if ( (this.state & INIT_MASK) == (this.mask & INIT_MASK) )
        {
            this.state |= ACTIVE;
        }
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the CONFIGURED state has already been set, if the component implements
     * Configurable, and if the state has progressed beyond the Configuration stage.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkConfigured( final String message )
    {
        if ( ( (this.state & this.mask & CONFIGURED) > 0 ) || ( (this.mask & CONFIGURED) == 0 ) || ( this.state > CONFIGURED ) )
        {
            throw new IllegalStateException( message );
        }

        this.state |= CONFIGURED;
        if ( (this.state & INIT_MASK) == (this.mask & INIT_MASK) )
        {
            this.state |= ACTIVE;
        }
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the INITIALIZED state has already been set, if the component implements
     * Initializable, and if the state has progressed beyond the <code>initialize</code> stage.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkInitialized( final String message )
    {
        if ( ( (this.state & this.mask & INITIALIZED) > 0 ) || ( (this.mask & INITIALIZED) == 0 ) || ( this.state > INITIALIZED ) )
        {
            throw new IllegalStateException( message );
        }

        this.state |= INITIALIZED;
        if ( (this.state & INIT_MASK) == (this.mask & INIT_MASK) )
        {
            this.state |= ACTIVE;
        }
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the STARTED state has already been set, if the component implements
     * Startable, and if the state has progressed beyond the <code>start</code> stage.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkStarted( final String message )
    {
        if ( ( (this.state & this.mask & STARTED) > 0 ) || ( (this.mask & STARTED) == 0 ) || ( this.state > STARTED ) )
        {
            throw new IllegalStateException( message );
        }

        this.state |= STARTED;
        if ( (this.state & INIT_MASK) == (this.mask & INIT_MASK) )
        {
            this.state |= ACTIVE;
        }
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the SUSPENDED state has already been set, if the component implements
     * Suspendable, and if the Component is active.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkSuspended( final String message )
    {
        checkActive( message );
        if ( ( (this.state & this.mask & SUSPENDED) > 0 ) || ( (this.mask & SUSPENDED) == 0 ) )
        {
            throw new IllegalStateException( message );
        }

        this.state |= SUSPENDED;
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the SUSPENDED state has not been set, if the component implements
     * Suspendable, and if the Component is active.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkResumed( final String message )
    {
        checkActive( message );
        if ( ( (this.state & this.mask & SUSPENDED) == 0 ) || ( (this.mask & SUSPENDED) == 0 ) )
        {
            throw new IllegalStateException( message );
        }

        this.state &= ~SUSPENDED;
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the STOPPED state has not been set, if the component implements
     * Startable, and if the Component is active.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkStopped( final String message )
    {
        if ( ( (this.state & this.mask & STOPPED) > 0 ) || ( (this.mask & STOPPED) == 0 ) || ( (this.state & this.mask) > STOPPED ) )
        {
            throw new IllegalStateException( message );
        }

        this.state &= ~ACTIVE;
        this.state |= STOPPED;
    }

    /**
     * Throw an exception if the initialization is out of order.  It tests to see
     * if the DISPOSED state has not been set, if the component implements
     * Disposable.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the state is manage out of order
     */
    public void checkDisposed( final String message )
    {
        if ( ( (this.state & this.mask & DISPOSED) > 0 ) || ( (this.mask & DISPOSED) == 0 ) )
        {
            throw new IllegalStateException( message );
        }

        this.state &= ~ACTIVE;
        this.state |= DISPOSED;
    }

    /**
     * Checks to see if the state is active.
     *
     * @param message the message to include in the thrown exception
     * @throws IllegalStateException if the component is not active
     */
    public void checkActive( final String message )
    {
        if ( (ACTIVE & this.state) > 0 ) {
            return;
        }

        throw new IllegalStateException( message );
    }
}

