/*******************************************************************************
 * Copyright 2008-2010 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use
 * this file except in compliance with the License. A copy of the License is located at
 *
 * http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.
 * *****************************************************************************
 *    __  _    _  ___
 *   (  )( \/\/ )/ __)
 *   /__\ \    / \__ \
 *  (_)(_) \/\/  (___/
 *
 *  AWS SDK for .NET
 *  API Version: 2009-11-30
 */

using System;
using System.Security;
using System.Security.Cryptography;
using System.Text;

using Amazon.Util;

namespace Amazon.EC2.Util
{
    /// <summary>
    /// This class represents S3 upload policy. Policy string
    /// representaion and signature to be used within EC2 bundling API.
    /// </summary>
    public class S3UploadPolicy
    {
        private string policySignature;
        private string policyString;
        private SecureString awsSecretAccessKey;
        private string clearAwsSecretAccessKey;

        /// <summary>
        /// S3 Upload policy to be used by EC2 API.
        /// </summary>
        /// <param name="awsAccessKeyId">Access Key Id of the signer of the policy</param>
        /// <param name="awsSecretAccessKey">Secret Key of the signer of the policy</param>
        /// <param name="bucketName">Bucket name to upload</param>
        /// <param name="prefix">Prefix for the object keys</param>
        /// <param name="expireInMinutes">Expire, minutes from now</param>
        public S3UploadPolicy(
            string awsAccessKeyId,
            SecureString awsSecretAccessKey,
            string bucketName,
            string prefix,
            int expireInMinutes)
        {
            string policy = BuildPolicyString(bucketName, prefix, expireInMinutes);
            this.policyString = Convert.ToBase64String(Encoding.UTF8.GetBytes(policy.ToCharArray()));
            this.awsSecretAccessKey = awsSecretAccessKey;
        }

        /// <summary>
        /// S3 Upload policy to be used by EC2 API.
        /// </summary>
        /// <param name="awsSecretAccessKey">Secret Key of the signer of the policy</param>
        /// <param name="bucketName">Bucket name to upload</param>
        /// <param name="prefix">Prefix for the object keys</param>
        /// <param name="expireInMinutes">Expire, minutes from now</param>
        public S3UploadPolicy(
            string awsSecretAccessKey,
            string bucketName,
            string prefix,
            int expireInMinutes)
        {
            string policy = BuildPolicyString(bucketName, prefix, expireInMinutes);
            this.policyString = Convert.ToBase64String(Encoding.UTF8.GetBytes(policy.ToCharArray()));
            this.clearAwsSecretAccessKey = awsSecretAccessKey;
        }

        /*
         * Builds the policy string based on the input parameters
         */
        private static string BuildPolicyString(
            string bucketName,
            string prefix,
            int expireInMinutes)
        {
            StringBuilder policy = new StringBuilder("{", 512);
            policy.Append("\"expiration\": \"");
            policy.Append(AWSSDKUtils.GetFormattedTimestampISO8601(expireInMinutes));
            policy.Append("\",");
            policy.Append("\"conditions\": [");
            policy.Append("{\"bucket\": \"");
            policy.Append(bucketName);
            policy.Append("\"},");
            policy.Append("{\"acl\": \"");
            policy.Append("ec2-bundle-read");
            policy.Append("\"},");
            policy.Append("[\"starts-with\", \"$key\", \"");
            policy.Append(prefix);
            policy.Append("\"]");
            policy.Append("]}");
            return policy.ToString();
        }

        /// <summary>
        /// Base64 representation of the serialized policy.
        /// Use policy generated by this method
        /// for passing to EC2 bunding calls.
        /// </summary>
        /// <returns>Base64 policy</returns>
        public string PolicyString
        {
            get
            {
                return this.policyString;
            }
        }

        /// <summary>
        /// Policy signature in base64 format
        /// Use signature generated by this method
        /// for passing to EC2 bunding calls along with policy.
        /// </summary>
        /// <returns>Base64 signature</returns>
        public string PolicySignature
        {
            get
            {
                if (this.policySignature == null)
                {
                    if (awsSecretAccessKey != null)
                    {
                        this.policySignature = AWSSDKUtils.HMACSign(
                            policyString,
                            awsSecretAccessKey,
                            new HMACSHA1()
                           );
                    }
                    else
                    {
                        this.policySignature = AWSSDKUtils.HMACSign(
                            policyString,
                            clearAwsSecretAccessKey,
                            new HMACSHA1()
                            );
                    }
                }
                return this.policySignature;
            }
        }
    }
}
