/*
 * Copyright 2014 the original author or authors.
 *
 * 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.cloudfoundry.community.servicebroker.s3.plan.basic;

import com.amazonaws.services.identitymanagement.model.AccessKey;
import com.amazonaws.services.identitymanagement.model.User;
import com.amazonaws.services.s3.model.Bucket;
import org.cloudfoundry.community.servicebroker.exception.ServiceBrokerException;
import org.cloudfoundry.community.servicebroker.model.ServiceDefinition;
import org.cloudfoundry.community.servicebroker.model.ServiceInstance;
import org.cloudfoundry.community.servicebroker.model.ServiceInstanceBinding;
import org.cloudfoundry.community.servicebroker.s3.plan.Plan;
import org.cloudfoundry.community.servicebroker.s3.service.S3;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class BasicPlan implements Plan {
    public static final String PLAN_ID = "s3-basic-plan";

    private final BasicPlanIam iam;
    private final S3 s3;

    @Autowired
    public BasicPlan(BasicPlanIam iam, S3 s3) {
        this.iam = iam;
        this.s3 = s3;
    }

    public static org.cloudfoundry.community.servicebroker.model.Plan getPlan() {
        return new org.cloudfoundry.community.servicebroker.model.Plan(PLAN_ID, "basic", "An S3 plan providing a single bucket with unlimited storage.",
                getPlanMetadata());
    }

    private static Map<String, Object> getPlanMetadata() {
        Map<String, Object> planMetadata = new HashMap<String, Object>();
        planMetadata.put("bullets", getPlanBullets());
        return planMetadata;
    }

    private static List<String> getPlanBullets() {
        return Arrays.asList("Single S3 bucket", "Unlimited storage", "Unlimited number of objects");
    }

    public ServiceInstance createServiceInstance(ServiceDefinition service, String serviceInstanceId, String planId,
                                                 String organizationGuid, String spaceGuid) {
        Bucket bucket = s3.createBucketForInstance(serviceInstanceId, service, planId, organizationGuid, spaceGuid);
        iam.createGroupForInstance(serviceInstanceId, bucket.getName());
        iam.applyGroupPolicyForInstance(serviceInstanceId, bucket.getName());
        return new ServiceInstance(serviceInstanceId, service.getId(), planId, organizationGuid, spaceGuid, null);
    }

    public ServiceInstance deleteServiceInstance(String id) {
        ServiceInstance instance = s3.findServiceInstance(id);
        // TODO we need to make these deletes idempotent so we can handle retries on error
        iam.deleteGroupPolicyForInstance(id);
        iam.deleteGroupForInstance(id);
        s3.emptyBucket(id);
        s3.deleteBucket(id);
        return instance;
    }

    public ServiceInstanceBinding createServiceInstanceBinding(String bindingId, ServiceInstance serviceInstance,
                                                               String serviceId, String planId, String appGuid) {
        User user = iam.createUserForBinding(bindingId);
        AccessKey accessKey = iam.createAccessKey(user);
        // TODO create password and add to credentials
        iam.addUserToGroup(user, iam.getGroupNameForInstance(serviceInstance.getId()));

        Map<String, Object> credentials = new HashMap<String, Object>();
        credentials.put("bucket", s3.getBucketNameForInstance(serviceInstance.getId()));
        credentials.put("username", user.getUserName());
        credentials.put("access_key_id", accessKey.getAccessKeyId());
        credentials.put("secret_access_key", accessKey.getSecretAccessKey());
        return new ServiceInstanceBinding(bindingId, serviceInstance.getId(), credentials, null, appGuid);
    }

    public ServiceInstanceBinding deleteServiceInstanceBinding(String bindingId, ServiceInstance serviceInstance,
                                                               String serviceId, String planId) throws ServiceBrokerException {
        // TODO make operations idempotent so we can handle retries on error
        iam.removeUserFromGroupForInstance(bindingId, serviceInstance.getId());
        iam.deleteUserAccessKeysForBinding(bindingId);
        iam.deleteUserForBinding(bindingId);
        return new ServiceInstanceBinding(bindingId, serviceInstance.getId(), null, null, null);
    }

    public List<ServiceInstance> getAllServiceInstances() {
        return s3.getAllServiceInstances();
    }

    public ServiceInstance getServiceInstance(String id) {
        return s3.findServiceInstance(id);
    }
}

@@ -1390,16 +1390,89 @@
 onent;%0A%0A
+import java.io.UnsupportedEncodingException;%0Aimport java.net.URLEncoder;%0A
 import j
@@ -1670,16 +1670,83 @@
 -plan%22;%0A
+    public static final String AMAZON_S3_HOST = %22s3.amazonaws.com%22;
 %0A    pri
@@ -4055,16 +4055,97 @@
 Id()));%0A
+        String bucketName = s3.getBucketNameForInstance(serviceInstance.getId());
 %0A       
@@ -4244,23 +4244,17 @@
 ucket%22, 
-s3.getB
+b
 ucketNam
@@ -4258,44 +4258,8 @@
 Name
-ForInstance(serviceInstance.getId())
 );%0A 
@@ -4474,104 +4474,839 @@
     
-return new ServiceInstanceBinding(bindingId, serviceInstance.getId(), credentials, null, appGuid
+credentials.put(%22host%22, AMAZON_S3_HOST);%0A        credentials.put(%22uri%22, this.generateUri(accessKey.getAccessKeyId(), accessKey.getSecretAccessKey(), bucketName));%0A        return new ServiceInstanceBinding(bindingId, serviceInstance.getId(), credentials, null, appGuid);%0A    %7D%0A%0A    private String generateUri(String accessKeyId, String secretAccessKey, String bucketName)%7B%0A        try %7B%0A            accessKeyId = URLEncoder.encode(accessKeyId, %22UTF-8%22);%0A            secretAccessKey = URLEncoder.encode(secretAccessKey, %22UTF-8%22);%0A        %7D catch (UnsupportedEncodingException e) %7B%0A            //let accessKeyId and secretAccessKey like they are%0A        %7D%0A        return String.format(%22s3://%25s:%25s@%25s/%25s%22,%0A                accessKeyId,%0A                secretAccessKey,%0A                AMAZON_S3_HOST,%0A                bucketName%0A        
 );%0A 

Add uri and host in credentials