/*
 * Copyright 2015 Bounce Storage, Inc. <info@bouncestorage.com>
 *
 * 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 com.bouncestorage.swiftproxy;

import static com.google.common.base.Throwables.propagate;

import java.net.URI;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import javax.ws.rs.core.MediaType;

import com.bouncestorage.swiftproxy.v1.InfoResource;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableMap;

import org.apache.commons.lang3.RandomStringUtils;

import org.glassfish.jersey.server.ResourceConfig;

import org.jclouds.Constants;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class BounceResourceConfig extends ResourceConfig {
    private static final Map<String, MediaType> swiftFormatToMediaType = ImmutableMap.of(
            "json", MediaType.APPLICATION_JSON_TYPE,
            "application/json", MediaType.APPLICATION_JSON_TYPE,
            "xml", MediaType.APPLICATION_XML_TYPE,
            "plain", MediaType.TEXT_PLAIN_TYPE
    );

    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final Properties properties;
    private URI endPoint;
    private BlobStoreLocator locator;
    private Cache<String, AuthenticatedBlobStore> tokensToBlobStore = CacheBuilder.newBuilder()
            .expireAfterWrite(InfoResource.CONFIG.tempauth.token_life, TimeUnit.SECONDS)
            .build();

    public interface AuthenticatedBlobStore {
        BlobStore get(String container, String key);
        default BlobStore get(String container) {
            return get(container, null);
        }
        default BlobStore get() {
            return get(null, null);
        }
    }

    BounceResourceConfig(Properties properties, BlobStoreLocator locator) {
        if (properties == null && locator == null) {
            throw new NullPointerException("One of properties or locator must be set");
        }
        this.properties = properties;
        this.locator = locator;
        packages(getClass().getPackage().getName());
    }

    public String authenticate(String identity, String credential) {
        AuthenticatedBlobStore blobStore = tryAuthenticate(identity, credential);
        if (blobStore != null) {
            String token = "AUTH_tk" + RandomStringUtils.randomAlphanumeric(32);
            tokensToBlobStore.put(token, blobStore);
            return token;
        }

        return null;
    }

    private AuthenticatedBlobStore tryAuthenticate(String identity, String credential) {
        if (locator != null) {
            Map.Entry<String, BlobStore> entry = locator.locateBlobStore(identity, null, null);
            if (entry != null && entry.getKey().equals(credential)) {
                logger.debug("blob store for {} found", identity);
                return (container, key) -> locator.locateBlobStore(identity, container, key).getValue();
            } else {
                logger.debug("blob store for {} not found", identity);
            }
        } else {
            logger.debug("fallback to authenticate with configured provider");
            try {
                BlobStoreContext context = ContextBuilder
                        .newBuilder(properties.getProperty(Constants.PROPERTY_PROVIDER))
                        .overrides(properties)
                        .credentials(identity, credential)
                        .build(BlobStoreContext.class);
                return (container, key) -> context.getBlobStore();
            } catch (Throwable e) {
                throw propagate(e);
            }
        }

        return null;
    }

    public AuthenticatedBlobStore getBlobStore(String authToken) {
        return tokensToBlobStore.getIfPresent(authToken);
    }

    public static MediaType getMediaType(String format) {
        return swiftFormatToMediaType.get(format);
    }

    public void setEndPoint(URI endPoint) {
        this.endPoint = endPoint;
    }

    public URI getEndPoint() {
        return endPoint;
    }

    public boolean isLocatorSet() {
        return locator != null;
    }

    public void setBlobStoreLocator(BlobStoreLocator newLocator) {
        locator = newLocator;
    }
}

@@ -1048,16 +1048,96 @@
 ableMap;
+%0Aimport com.google.common.collect.ImmutableSet;%0Aimport com.google.inject.Module;
 %0A%0Aimport
@@ -1386,16 +1386,76 @@
 ontext;%0A
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;%0A
 import o
@@ -4225,16 +4225,100 @@
 ential)%0A
+                        .modules(ImmutableSet.%3CModule%3Eof(new SLF4JLoggingModule()))%0A
         

use logback to configure created blobstores