/*
 * #%L
 * wcm.io
 * %%
 * Copyright (C) 2014 wcm.io
 * %%
 * 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.
 * #L%
 */
package io.wcm.caravan.commons.couchbase.impl;

import io.wcm.caravan.commons.couchbase.CouchbaseClient;

import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.couchbase.client.java.AsyncBucket;
import com.couchbase.client.java.Cluster;

/**
 * Default implementation of {@link CouchbaseClient}.
 */
@Component(immediate = true, metatype = true,
label = "wcm.io Caravan Couchbase Client Provider",
description = "Provides access to a preconfigured couchbase client.",
configurationFactory = true, policy = ConfigurationPolicy.REQUIRE)
@Service(CouchbaseClient.class)
@Property(name = "webconsole.configurationFactory.nameHint", value = "{clientId}: {cacheBucketName}")
public class CouchbaseClientImpl implements CouchbaseClient {

  @Property(label = "Client ID", description = "ID to uniquely identify the couchbase client if multiple are defined.")
  private static final String CLIENT_ID_PROPERTY = CouchbaseClient.CLIENT_ID_PROPERTY;

  @Property(label = "Enabled", description = "Enable or disable couchbase caching.",
      boolValue = CouchbaseClientImpl.ENABLED_PROPERTY_DEFAULT)
  private static final String ENABLED_PROPERTY = "enabled";
  private static final boolean ENABLED_PROPERTY_DEFAULT = true;

  @Property(label = "Couchbase Hosts", description = "Couchbase cluster host list.",
      cardinality = Integer.MAX_VALUE)
  private static final String COUCHBASE_HOSTS_PROPERTY = "couchbaseHosts";

  @Property(label = "Bucket Name", description = "Couchbase bucket name")
  private static final String CACHE_BUCKET_NAME_PROPERTY = "bucketName";

  @Property(label = "Bucket Password", description = "Couchbase bucket password")
  private static final String CACHE_BUCKET_PASSWORD_PROPERTY = "bucketPassword";

  private static final Logger log = LoggerFactory.getLogger(CouchbaseClientImpl.class);

  private String clientId;
  private boolean enabled;
  private String bucketName;
  private Cluster cluster;
  private AsyncBucket bucket;

  @Activate
  private void activate(Map<String, Object> config) {
    clientId = PropertiesUtil.toString(config.get(CLIENT_ID_PROPERTY), null);
    enabled = PropertiesUtil.toBoolean(config.get(ENABLED_PROPERTY), ENABLED_PROPERTY_DEFAULT);
    if (!enabled) {
      log.info("Couchbase caching for client '{}' is disabled by configuration.", clientId);
      return;
    }

    String[] couchbaseHosts = PropertiesUtil.toStringArray(config.get(COUCHBASE_HOSTS_PROPERTY));
    if (couchbaseHosts == null || couchbaseHosts.length == 0) {
      enabled = false;
      log.warn("No couchbase host configured, client '{}' is disabled.", clientId);
      return;
    }

    bucketName = PropertiesUtil.toString(config.get(CACHE_BUCKET_NAME_PROPERTY), null);
    String bucketPassword = PropertiesUtil.toString(config.get(CACHE_BUCKET_PASSWORD_PROPERTY), null);
    if (StringUtils.isEmpty(bucketName)) {
      enabled = false;
      log.warn("No couchbase bucket name configured, client '{}' is disabled.", clientId);
      return;
    }

    try {
      cluster = CouchbaseUtil.createCluster(couchbaseHosts);
      bucket = CouchbaseUtil.openBucket(cluster, bucketName, bucketPassword);
    }
    catch (Throwable ex) {
      enabled = false;
      log.warn("Unable to connect to couchbase cluster or open couchbase bucket, client '" + clientId + "' is disabled.", ex);
    }
  }

  @Deactivate
  private void deactivate() {
    if (bucket != null) {
      bucket.close();
      bucket = null;
    }
    if (cluster != null) {
      cluster.disconnect();
      cluster = null;
    }
  }

  @Override
  public String getClientId() {
    return clientId;
  }

  @Override
  public boolean isEnabled() {
    return enabled;
  }

  @Override
  public String getBucketName() {
    return bucketName;
  }

  @Override
  public AsyncBucket getBucket() {
    return bucket;
  }

}

@@ -1697,17 +1697,17 @@
 meHint%22,
- 
+%0A
 value = 
@@ -1712,35 +1712,112 @@
 = %22%7B
-clientId%7D: %7BcacheBucketName
+%22 + CouchbaseClientImpl.CLIENT_ID_PROPERTY + %22%7D: %7B%22 + CouchbaseClientImpl.CACHE_BUCKET_NAME_PROPERTY + %22
 %7D%22)%0A
@@ -1997,32 +1997,24 @@
 efined.%22)%0A  
-private 
 static final
@@ -2226,32 +2226,24 @@
 _DEFAULT)%0A  
-private 
 static final
@@ -2467,32 +2467,24 @@
 AX_VALUE)%0A  
-private 
 static final
@@ -2609,32 +2609,24 @@
 et name%22)%0A  
-private 
 static final
@@ -2759,26 +2759,18 @@
 sword%22)%0A
+
   
-private 
 static f

fix name hint