package org.codehaus.plexus.interpolation.fixed;

/*
 * Copyright 2014 The Codehaus Foundation.
 *
 * 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.
 */

import java.io.IOException;
import java.util.Properties;

import org.codehaus.plexus.interpolation.os.OperatingSystemUtils;

/**
 * {@link org.codehaus.plexus.interpolation.ValueSource} which resolves expressions against the environment variables
 * available from the underlying operating system (and possibly, the shell environment
 * that created the present Java process). If the expression starts with 'env.',
 * this prefix is trimmed before resolving the rest as an environment variable name.
 *
 */
public class EnvarBasedValueSource implements FixedValueSource {

    private static Properties envarsCaseSensitive;
    private static Properties envarsCaseInsensitive;

    private final Properties envars;
    private final boolean caseSensitive;

    /**
     * Create a new value source for interpolation based on shell environment variables. In this
     * case, envar keys ARE CASE SENSITIVE.
     *
     * @throws java.io.IOException in case of an error.
     */
    public EnvarBasedValueSource() throws IOException {
        this(true);
    }

    /**
     * Create a new value source for interpolation based on shell environment variables.
     *
     * @param caseSensitive Whether the environment variable key should be treated in a
     *                      case-sensitive manner for lookups
     * @throws java.io.IOException in case of an error.
     */
    public EnvarBasedValueSource(boolean caseSensitive) throws IOException {
        this.caseSensitive = caseSensitive;
        this.envars = getEnvars(caseSensitive);
    }

    private static synchronized Properties getEnvars(boolean caseSensitive) throws IOException {
        if (caseSensitive) {
            if (envarsCaseSensitive == null) {
                envarsCaseSensitive = OperatingSystemUtils.getSystemEnvVars(caseSensitive);
            }
            return envarsCaseSensitive;
        } else {
            if (envarsCaseInsensitive == null) {
                envarsCaseInsensitive = OperatingSystemUtils.getSystemEnvVars(caseSensitive);
            }
            return envarsCaseInsensitive;
        }
    }

    /**
     * If the expression starts with 'env.' then trim this prefix. Next, resolve
     * the (possibly trimmed) expression as an environment variable name against
     * the collection of environment variables that were read from the operating
     * system when this {@link org.codehaus.plexus.interpolation.ValueSource} instance was created.
     *
     * @param expression envar expression, like 'HOME' or 'env.HOME'
     * @return the environment variable value for the given expression
     */
    public Object getValue(String expression, InterpolationState interpolationState) {
        String expr = expression;

        if (expr.startsWith("env.")) {
            expr = expr.substring("env.".length());
        }

        if (!caseSensitive) {
            expr = expr.toUpperCase();
        }

        return envars.getProperty(expr);
    }

    /**
     * reset static variables acting as a cache for testing purposes only
     */
    static void resetStatics() {
        envarsCaseSensitive = null;
        envarsCaseInsensitive = null;
    }
}
