/*
 * Copyright 2019 MovingBlocks
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.terasology.gestalt.assets.management;

import com.google.common.collect.Queues;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.gestalt.naming.Name;

import java.util.Deque;

/**
 * ContextManager provides the ability to set the module context in which a thread is currently running, and this context can be checked. In the asset system this
 * is used to have the current context influence the resolution of assets.
 *
 * @author Immortius
 */
public final class ContextManager {

    private static final Logger logger = LoggerFactory.getLogger(ContextManager.class);
    private static final ThreadLocal<Deque<Name>> CONTEXT_STACK = ThreadLocal.withInitial(Queues::newArrayDeque);

    private ContextManager() {
    }

    /**
     * @return The Name of the module that is the current context of the thread. If there is no current context the result will be Name.EMPTY.
     */
    public static Name getCurrentContext() {
        Name context = CONTEXT_STACK.get().peek();
        return (context != null) ? context : Name.EMPTY;
    }

    /**
     * Sets the current context and returns a resource that should be closed when the context ends.
     *
     * @param moduleId The name of the module to make the current context
     * @return A Context object that should be closed when the context ends. This will restore the preceding context if any.
     */
    public static Context beginContext(final Name moduleId) {
        CONTEXT_STACK.get().push(moduleId);
        return new Context() {

            @Override
            public Name getContext() {
                return moduleId;
            }

            @Override
            public void close() {
                Deque<Name> stack = CONTEXT_STACK.get();
                if (!moduleId.equals(stack.pop())) {
                    logger.error("Module context ended out of sequence");
                }
                if (stack.isEmpty()) {
                    CONTEXT_STACK.remove();
                }
            }
        };
    }
}

/*
 * Copyright 2019 MovingBlocks
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.terasology.gestalt.assets.management;

import com.google.common.collect.Queues;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.gestalt.naming.Name;

import java.util.Deque;

/**
 * ContextManager provides the ability to set the module context in which a thread is currently running, and this context can be checked. In the asset system this
 * is used to have the current context influence the resolution of assets.
 *
 * @author Immortius
 */
public final class ContextManager {

    private static final Logger logger = LoggerFactory.getLogger(ContextManager.class);
    private static final ThreadLocal<Deque<Name>> CONTEXT_STACK = new ThreadLocal<Deque<Name>>() {
        @Override
        protected Deque<Name> initialValue() {
            return Queues.newArrayDeque();
        }
    };

    private ContextManager() {
    }

    /**
     * @return The Name of the module that is the current context of the thread. If there is no current context the result will be Name.EMPTY.
     */
    public static Name getCurrentContext() {
        Name context = CONTEXT_STACK.get().peek();
        return (context != null) ? context : Name.EMPTY;
    }

    /**
     * Sets the current context and returns a resource that should be closed when the context ends.
     *
     * @param moduleId The name of the module to make the current context
     * @return A Context object that should be closed when the context ends. This will restore the preceding context if any.
     */
    public static Context beginContext(final Name moduleId) {
        CONTEXT_STACK.get().push(moduleId);
        return new Context() {

            @Override
            public Name getContext() {
                return moduleId;
            }

            @Override
            public void close() {
                Deque<Name> stack = CONTEXT_STACK.get();
                if (!moduleId.equals(stack.pop())) {
                    logger.error("Module context ended out of sequence");
                }
                if (stack.isEmpty()) {
                    CONTEXT_STACK.remove();
                }
            }
        };
    }
}

remove only use of Android API 24 incompatible code