/*
 * Copyright 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.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using Amazon.DynamoDBv2.Model;
using System.IO;
using Amazon.Util;
namespace Amazon.DynamoDBv2.DocumentModel
{
    /// 
    /// Expected state of an attribute in DynamoDB.
    /// Exists cannot be set at the same time as Comparison and Values.
    /// 
    public class ExpectedValue
    {
        /// 
        /// Flag whether the attribute should exist or not.
        /// 
        public bool Exists { get; set; }
        /// 
        /// Comparison operator for the expected value.
        /// 
        public ScanOperator Comparison { get; private set; }
        /// 
        /// Values to compare the attribute against.
        /// 
        public List Values { get; private set; }
        /// 
        /// Constructs an ExpectedValue with a given Exists value.
        /// 
        /// 
        /// Flag whether the attribute should exist or not.
        /// 
        public ExpectedValue(bool exists)
        {
            Exists = exists;
            Values = new List();
        }
        /// 
        /// Constructs an ExpectedValue with a given comparison and value(s).
        /// 
        /// 
        /// 
        public ExpectedValue(ScanOperator comparison, params Primitive[] values)
        {
            Exists = true;
            Comparison = comparison;
            Values = new List(values);
        }
        /// 
        /// Converts this ExpectedValue instance to Amazon.DynamoDBv2.Model.ExpectedAttributeValue
        /// This call will use the conversion specified by AWSConfigs.DynamoDBConfig.ConversionSchema
        /// 
        /// Amazon.DynamoDBv2.Model.ExpectedAttributeValue
        public ExpectedAttributeValue ToExpectedAttributeValue()
        {
            return ToExpectedAttributeValue(DynamoDBEntryConversion.CurrentConversion, false);
        }
        /// 
        /// Converts this ExpectedValue instance to Amazon.DynamoDBv2.Model.ExpectedAttributeValue
        /// 
        /// Conversion to use for converting .NET values to DynamoDB values.
        /// Amazon.DynamoDBv2.Model.ExpectedAttributeValue
        public ExpectedAttributeValue ToExpectedAttributeValue(DynamoDBEntryConversion conversion)
        {
            return ToExpectedAttributeValue(this.Exists, this.Values.Cast(), this.Comparison, conversion, false);
        }
        /// 
        /// Converts this ExpectedValue instance to Amazon.DynamoDBv2.Model.ExpectedAttributeValue
        /// 
        /// Conversion to use for converting .NET values to DynamoDB values.
        /// 
        /// Amazon.DynamoDBv2.Model.ExpectedAttributeValue
        public ExpectedAttributeValue ToExpectedAttributeValue(DynamoDBEntryConversion conversion, bool isEmptyStringValueEnabled)
        {
            return ToExpectedAttributeValue(this.Exists, this.Values.Cast(), this.Comparison, conversion, isEmptyStringValueEnabled);
        }
        internal static ExpectedAttributeValue ToExpectedAttributeValue(bool exists, IEnumerable values,
            ScanOperator comparison, DynamoDBEntryConversion conversion, bool isEmptyStringValueEnabled)
        {
            var eav = new ExpectedAttributeValue();
            if (exists)
            {
                eav.ComparisonOperator = EnumMapper.Convert(comparison);
                foreach (var val in values)
                {
                    var attributeConversionConfig = new DynamoDBEntry.AttributeConversionConfig(conversion, isEmptyStringValueEnabled);
                    eav.AttributeValueList.Add(val.ConvertToAttributeValue(attributeConversionConfig));
                }
            }
            else
                eav.Exists = exists;
            return eav;
        }
    }
    /// 
    /// Expected state of an item in DynamoDB.
    /// 
    public class ExpectedState
    {
        /// 
        /// Constructs an empty ExpectedState with ConditionalOeprator set to AND.
        /// 
        public ExpectedState()
        {
            ExpectedValues = new Dictionary(StringComparer.Ordinal);
            ConditionalOperator = ConditionalOperatorValues.And;
        }
        /// 
        /// Attribute name to ExpectedValue mapping.
        /// Represents the expected state of a number of attributes of a DynamoDB item.
        /// 
        public Dictionary ExpectedValues { get; set; }
        /// 
        /// Operator dictating whether ALL or SOME of the expected values must be true to
        /// satisfy the overall expected state.
        /// 
        public ConditionalOperatorValues ConditionalOperator { get; set; }
        /// 
        /// Adds an ExpectedValue with the specific Exists value for the attribute.
        /// 
        /// Attribute that is being tested
        /// Flag whether the attribute should exist or not.
        public void AddExpected(string attributeName, bool exists)
        {
            ExpectedValues[attributeName] = new ExpectedValue(exists);
        }
        /// 
        /// Adds an ExpectedValue with the specific Comparison and Values for the attribute.
        /// 
        /// Attribute that is being tested
        /// Comparison operator for the expected value.
        /// Values to compare the attribute against.
        public void AddExpected(string attributeName, ScanOperator comparison, params Primitive[] values)
        {
            ExpectedValues[attributeName] = new ExpectedValue(comparison, values);
        }
        /// 
        /// Creates a map of attribute names mapped to ExpectedAttributeValue objects.
        /// This call will use the conversion specified by AWSConfigs.DynamoDBConfig.ConversionSchema
        /// 
        /// 
        public Dictionary ToExpectedAttributeMap()
        {
            return ToExpectedAttributeMap(DynamoDBEntryConversion.CurrentConversion);
        }
        /// 
        /// Creates a map of attribute names mapped to ExpectedAttributeValue objects.
        /// 
        /// Conversion to use for converting .NET values to DynamoDB values.
        /// 
        public Dictionary ToExpectedAttributeMap(DynamoDBEntryConversion conversion)
        {
            return ToExpectedAttributeMap(conversion, epochAttributes: null, isEmptyStringValueEnabled: false);
        }
        /// 
        /// Creates a map of attribute names mapped to ExpectedAttributeValue objects.
        /// This call will use the conversion specified in the table.
        /// 
        /// 
        public Dictionary ToExpectedAttributeMap(Table table)
        {
            return ToExpectedAttributeMap(table.Conversion, table.StoreAsEpoch, table.IsEmptyStringValueEnabled);
        }
        private Dictionary ToExpectedAttributeMap(DynamoDBEntryConversion conversion,
            IEnumerable epochAttributes, bool isEmptyStringValueEnabled)
        {
            Dictionary ret = new Dictionary();
            foreach (var kvp in ExpectedValues)
            {
                string attributeName = kvp.Key;
                ExpectedValue expectedValue = kvp.Value;
                ExpectedAttributeValue eav;
                if (epochAttributes != null && epochAttributes.Contains(attributeName))
                {
                    var values = expectedValue.Values.Select(p => Document.DateTimeToEpochSeconds(p, attributeName)).ToList();
                    eav = ExpectedValue.ToExpectedAttributeValue(expectedValue.Exists, values, expectedValue.Comparison, conversion, isEmptyStringValueEnabled);
                }
                else
                {
                    eav = expectedValue.ToExpectedAttributeValue(conversion, isEmptyStringValueEnabled);
                }
                ret[attributeName] = eav;
            }
            return ret;
        }
    }
}