/*
 *  Copyright (c) 2005-2012, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you 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.apache.synapse.commons.throttle.core;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.securevault.SecretResolver;
import org.wso2.securevault.SecretResolverFactory;
import org.wso2.securevault.commons.MiscellaneousUtil;

import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.Caching;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

public class ThrottleUtil {

    private static Log log = LogFactory.getLog(ThrottleUtil.class.getName());

    public static final String THROTTLING_CACHE_MANAGER = "throttling.cache.manager";

    private static final String CONF_LOCATION = "conf.location";

    public static final String THROTTLING_CACHE = "throttling.cache";

    /**
     * This method used to set throttle properties loaded from throttle.properties file in configuration folder
     *
     * @return properties of throttle properties
     */
	public static ThrottleProperties loadThrottlePropertiesFromConfigurations() {

		ThrottleProperties throttleProperties = new ThrottleProperties();
		Properties properties = new Properties();
		String throttlePropertiesFileLocation;
		if (System.getProperty(CONF_LOCATION) != null) {
			throttlePropertiesFileLocation = System.getProperty(CONF_LOCATION) + File.separator + "throttle.properties";
			try {
				properties.load(new FileInputStream(throttlePropertiesFileLocation));
				SecretResolver secretResolver = SecretResolverFactory.create(properties);
				Set<String> keys = properties.stringPropertyNames();
				for (String key : keys) {
					if (ThrottleConstants.THROTTLE_CONTEXT_CLEANUP_TASK_FREQUENCY.equals(key)) {
						String throttleFrequency = properties.getProperty(key);
						if (!StringUtils.isEmpty(throttleFrequency)) {
							throttleProperties.setThrottleFrequency(throttleFrequency);
						}
					}
					if (ThrottleConstants.THROTTLE_CONTEXT_DISTRIBUTED_CLEANUP_TASK_FREQUENCY.equals(key)) {
						String throttleContextDistributedCleanupTaskFrequency = properties.getProperty(key);
						if (throttleContextDistributedCleanupTaskFrequency != null &&
								!throttleContextDistributedCleanupTaskFrequency.equals("")) {
							throttleProperties.setThrottleContextDistributedCleanupTaskFrequency(
									throttleContextDistributedCleanupTaskFrequency);
						}
					}
					if (ThrottleConstants.THROTTLE_CONTEXT_DISTRIBUTED_EXPIRED_INSTANCE_TIME.equals(key)) {
						String throttleContextDistributedExpiredInstanceTime = properties.getProperty(key);
						if (throttleContextDistributedExpiredInstanceTime != null &&
								!throttleContextDistributedExpiredInstanceTime.equals("")) {
							throttleProperties.setThrottleContextDistributedExpiredInstanceTime(
									throttleContextDistributedExpiredInstanceTime);
						}
					}
					if (ThrottleConstants.THROTTLE_DISTRIBUTED_CLEANUP_POOL_SIZE.equals(key)) {
						String throttleDistributedCleanupPoolSize = properties.getProperty(key);
						if (throttleDistributedCleanupPoolSize != null && throttleDistributedCleanupPoolSize != "") {
							throttleProperties.setThrottleDistributedCleanupPoolSize(throttleDistributedCleanupPoolSize);
						}
					}
					if (ThrottleConstants.THROTTLE_DISTRIBUTED_CLEANUP_AMOUNT.equals(key)) {
						String throttleDistributedCleanupAmount = properties.getProperty(key);
						if (throttleDistributedCleanupAmount != null && throttleDistributedCleanupAmount != "") {
							throttleProperties.setThrottleDistributedCleanupAmount(
									throttleDistributedCleanupAmount);

						}
					}
					if (ThrottleConstants.THROTTLE_DISTRIBUTED_CLEANUP_TASK_ENABLE.equals(key)) {
						String throttleDistributedCleanupTaskEnable = properties.getProperty(key);
						if (throttleDistributedCleanupTaskEnable != null && throttleDistributedCleanupTaskEnable !=
								"") {
							throttleProperties.setThrottleDistributedCleanupTaskEnable(
									throttleDistributedCleanupTaskEnable);
						}
					}
					if (ThrottleConstants.MAX_NON_ASSOCIATED_COUNTER_CLEANUP_AMOUNT.equals(key)) {
						String maxNonAssociatedCounterCleanupAmount = properties.getProperty(key);
						if (maxNonAssociatedCounterCleanupAmount != null && maxNonAssociatedCounterCleanupAmount !=
								"") {
							throttleProperties.setMaxNonAssociatedCounterCleanupAmount(
									maxNonAssociatedCounterCleanupAmount);
						}
					}
					if (ThrottleConstants.THROTTLING_POOL_SIZE.equals(key)) {
						String throttlingPoolSize = properties.getProperty(key);
						if (throttlingPoolSize != null && throttlingPoolSize != "") {
							throttleProperties.setThrottlingPoolSize(throttlingPoolSize);
						}
					}
					if (ThrottleConstants.THROTTLING_REPLICATION_FREQUENCY.equals(key)) {
						String throttlingReplicationFrequency = properties.getProperty(key);
						if (throttlingReplicationFrequency != null && throttlingReplicationFrequency != "") {
							throttleProperties.setThrottlingReplicationFrequency(
									throttlingReplicationFrequency);
						}
					}
					if (ThrottleConstants.THROTTLING_KEYS_TO_REPLICATE.equals(key)) {
						String throttlingKeysToReplicate = properties.getProperty(key);
						if (throttlingKeysToReplicate != null && throttlingKeysToReplicate != "") {
							throttleProperties.setThrottlingKeysToReplicates(throttlingKeysToReplicate);
						}
					}
					if (ThrottleConstants.WINDOW_REPLICATOR_POOL_SIZE.equals(key)) {
						String windowReplicatorPoolSize = properties.getProperty(key);
						if (windowReplicatorPoolSize != null && windowReplicatorPoolSize != "") {
							throttleProperties.setWindowReplicatorPoolSize(windowReplicatorPoolSize);
						}
					}
					if (ThrottleConstants.WINDOW_REPLICATOR_FREQUENCY.equals(key)) {
						String windowReplicatorFrequency = properties.getProperty(key);
						if (windowReplicatorFrequency != null && windowReplicatorFrequency != "") {
							throttleProperties.setWindowReplicatorFrequency(
									windowReplicatorFrequency);
						}
					}
					if (ThrottleConstants.DISTRIBUTED_COUNTER_TYPE.equals(key)) {
						String distributedCounterType =
								properties.getProperty(key);
						if (distributedCounterType != null && !distributedCounterType.equals("")) {
							throttleProperties.setDistributedCounterType(distributedCounterType);
						}
					}
					if (key.contains(ThrottleConstants.DISTRIBUTED_COUNTER_CONFIGURATIONS)) {
						String distributedConfiguration = properties.getProperty(key);
						String configuration = key.split(ThrottleConstants.DISTRIBUTED_COUNTER_CONFIGURATIONS)[1];
						if (StringUtils.isNotEmpty(distributedConfiguration)) {
							throttleProperties.getDistributedCounterConfigurations().put(configuration,
									getResolvedValue(secretResolver, distributedConfiguration));
						}
					}
					if (key.contains(ThrottleConstants.THROTTLE_SYNC_ASYNC_HYBRID_MODE_ENABLED)) {
						String throttleSyncAsyncHybridModeEnabled = properties.getProperty(key);
						if (StringUtils.isNotEmpty(throttleSyncAsyncHybridModeEnabled)) {
							throttleProperties.setThrottleSyncAsyncHybridModeEnabled(
									Boolean.parseBoolean(throttleSyncAsyncHybridModeEnabled));
						}
					}
					if (key.contains(ThrottleConstants.HYBRID_THROTTLE_PROCESSOR_WINDOW_TYPE)) {
						String hybridThrottleProcessorWindowType = properties.getProperty(key);
						if (StringUtils.isNotEmpty(hybridThrottleProcessorWindowType)) {
							throttleProperties.setHybridThrottleProcessorWindowType(hybridThrottleProcessorWindowType);
						}
					}
					if (key.contains(ThrottleConstants.LOCAL_QUOTA_BUFFER_PERCENTAGE)) {
						String localQuotaBufferPercentage = properties.getProperty(key);
						if (StringUtils.isNotEmpty(localQuotaBufferPercentage)) {
							throttleProperties.setLocalQuotaBufferPercentage(localQuotaBufferPercentage);
						}
					}
				}
			} catch (IOException e) {
				log.debug("Setting the Default Throttle Properties");
			}
		} else {
			log.debug("Setting the Default Throttle Properties");
		}

		return throttleProperties;

	}

	private static String getResolvedValue(SecretResolver secretResolver, String value) {

		if (secretResolver.isInitialized()) {
			return MiscellaneousUtil.resolve(value, secretResolver);
		}
		return value;
	}
        public static Cache<String, CallerContext> getThrottleCache () {
            // acquiring  cache manager.
            Cache<String, CallerContext> cache;
            CacheManager cacheManager = Caching.getCacheManagerFactory().
                    getCacheManager(THROTTLING_CACHE_MANAGER);
            if (cacheManager != null) {
                cache = cacheManager.getCache(THROTTLING_CACHE);
            } else {
                cache = Caching.getCacheManager().getCache(THROTTLING_CACHE);
            }
            if (log.isDebugEnabled()) {
                log.debug("created throttling cache : " + cache);
            }
            return cache;
        }
}
