/// <summary>
        /// Performs a deep clone of a parameter transformation.
        /// </summary>
        /// <returns>A deep clone of current object.</returns>
        public object Clone()
        {
            //ParameterTransformation paramTransformation = (ParameterTransformation)this.MemberwiseClone();
            //return paramTransformation;

            var transformation = new ParameterTransformation();
            transformation.OutputParameter = (Parameter) this.OutputParameter.Clone();
            this.ParameterMappings.ToList().ForEach(pm => transformation.ParameterMappings.Add((ParameterMapping) pm.Clone()));
            return transformation;
        }
 private static string BuildNullCheckExpression(ParameterTransformation transformation)
 {
     if (transformation == null)
     {
         throw new ArgumentNullException("transformation");
     }
     if (transformation.ParameterMappings.Count == 1)
     {
         return string.Format(CultureInfo.InvariantCulture,
             "{0} !== null && {0} !== undefined",
             transformation.ParameterMappings[0].InputParameter.Name);
     }
     else
     {
         return string.Join(" || ",
         transformation.ParameterMappings.Select(m =>
             string.Format(CultureInfo.InvariantCulture,
             "({0} !== null && {0} !== undefined)", m.InputParameter.Name)));
     }
 }
        /// <summary>
        /// Flattens the request payload if the number of properties of the 
        /// payload is less than or equal to the PayloadFlatteningThreshold.
        /// </summary>
        /// <param name="serviceClient">Service client</param>                            
        /// <param name="settings">AutoRest settings</param>                            
        public static void FlattenMethodParameters(ServiceClient serviceClient, Settings settings)
        {
            if (serviceClient == null)
            {
                throw new ArgumentNullException("serviceClient");    
            }
            if (settings == null)
            {
                throw new ArgumentNullException("settings");
            }

            foreach (var method in serviceClient.Methods)
            {
                var bodyParameter = method.Parameters.FirstOrDefault(
                    p => p.Location == ParameterLocation.Body);

                if (bodyParameter != null)
                {
                    var bodyParameterType = bodyParameter.Type as CompositeType;
                    if (bodyParameterType != null && 
                        (bodyParameterType.ComposedProperties.Count(p => !p.IsConstant) <= settings.PayloadFlatteningThreshold ||
                         bodyParameter.ShouldBeFlattened()))
                    {
                        var parameterTransformation = new ParameterTransformation
                        {
                            OutputParameter = bodyParameter
                        };
                        method.InputParameterTransformation.Add(parameterTransformation);

                        foreach (var property in bodyParameterType.ComposedProperties.Where(p => !p.IsConstant && p.Name != null))
                        {
                            var newMethodParameter = new Parameter();
                            newMethodParameter.LoadFrom(property);

                            var documentationString = !string.IsNullOrEmpty(property.Summary) ? property.Summary + " " : string.Empty;
                            documentationString += property.Documentation;
                            newMethodParameter.Documentation = documentationString;

                            bodyParameter.Extensions.ForEach(kv => { newMethodParameter.Extensions[kv.Key] = kv.Value; });
                            method.Parameters.Add(newMethodParameter);

                            parameterTransformation.ParameterMappings.Add(new ParameterMapping
                            {
                                InputParameter = newMethodParameter,
                                OutputParameterProperty = property.GetClientName()
                            });
                        }

                        method.Parameters.Remove(bodyParameter);
                    }
                }
            }
        }
        private static string BuildNullCheckExpression(ParameterTransformation transformation)
        {
            if (transformation == null)
            {
                throw new ArgumentNullException("transformation");
            }

            return string.Join(" || ",
                transformation.ParameterMappings
                    .Where(m => !m.InputParameter.Type.IsValueType())
                    .Select(m => m.InputParameter.Name + " != null"));
        }
        private static string BuildNullCheckExpression(ParameterTransformation transformation)
        {
            if (transformation == null)
            {
                throw new ArgumentNullException("transformation");
            }

            return string.Join(" or ",
                transformation.ParameterMappings.Select(m =>
                    string.Format(CultureInfo.InvariantCulture,
                    "{0} is not None", m.InputParameter.Name)));
        }
        /// <summary>
        /// Adds the parameter groups to operation parameters.
        /// </summary>
        /// <param name="serviceClient"></param>
        public static void AddParameterGroups(ServiceClient serviceClient)
        {
            if (serviceClient == null)
            {
                throw new ArgumentNullException("serviceClient");
            }

            HashSet<CompositeType> generatedParameterGroups = new HashSet<CompositeType>();

            foreach (Method method in serviceClient.Methods)
            {
                //Copy out flattening transformations as they should be the last
                List<ParameterTransformation> flatteningTransformations = method.InputParameterTransformation.ToList();
                method.InputParameterTransformation.Clear();

                //This group name is normalized by each languages code generator later, so it need not happen here.
                IEnumerable<ParameterGroup> parameterGroups = ExtractParameterGroups(method);

                List<Parameter> parametersToAddToMethod = new List<Parameter>();
                List<Parameter> parametersToRemoveFromMethod = new List<Parameter>();

                foreach (ParameterGroup parameterGroup in parameterGroups)
                {
                    CompositeType parameterGroupType =
                        generatedParameterGroups.FirstOrDefault(item => item.Name == parameterGroup.Name);

                    if (parameterGroupType == null)
                    {
                        IEnumerable<Method> methodsWhichUseGroup = GetMethodsUsingParameterGroup(serviceClient.Methods, parameterGroup);

                        parameterGroupType = new CompositeType
                        {
                            Name = parameterGroup.Name,
                            Documentation = GenerateParameterGroupModelText(methodsWhichUseGroup)
                        };
                        generatedParameterGroups.Add(parameterGroupType);

                        //Add to the service client
                        serviceClient.ModelTypes.Add(parameterGroupType);
                    }

                    foreach (Property property in parameterGroup.ParameterMapping.Keys)
                    {
                        Property matchingProperty = parameterGroupType.Properties.FirstOrDefault(
                                item => item.Name == property.Name &&
                                        item.IsReadOnly == property.IsReadOnly &&
                                        item.DefaultValue == property.DefaultValue &&
                                        item.SerializedName == property.SerializedName);
                        if (matchingProperty == null)
                        {
                            parameterGroupType.Properties.Add(property);
                        }
                    }

                    bool isGroupParameterRequired = parameterGroupType.Properties.Any(p => p.IsRequired);

                    //Create the new parameter object based on the parameter group type
                    Parameter newParameter = new Parameter()
                    {
                        Name = parameterGroup.Name,
                        IsRequired = isGroupParameterRequired,
                        Location = ParameterLocation.None,
                        SerializedName = string.Empty,
                        Type = parameterGroupType,
                        Documentation = "Additional parameters for the operation"
                    };
                    parametersToAddToMethod.Add(newParameter);

                    //Link the grouped parameters to their parent, and remove them from the method parameters
                    foreach (Property property in parameterGroup.ParameterMapping.Keys)
                    {
                        Parameter p = parameterGroup.ParameterMapping[property];

                        var parameterTransformation = new ParameterTransformation
                        {
                            OutputParameter = p
                        };

                        parameterTransformation.ParameterMappings.Add(new ParameterMapping
                        {
                            InputParameter = newParameter,
                            InputParameterProperty = property.GetClientName()
                        });
                        method.InputParameterTransformation.Add(parameterTransformation);
                        parametersToRemoveFromMethod.Add(p);
                    }
                }

                method.Parameters.RemoveAll(p => parametersToRemoveFromMethod.Contains(p));
                method.Parameters.AddRange(parametersToAddToMethod);

                // Copy back flattening transformations if any
                flatteningTransformations.ForEach(t => method.InputParameterTransformation.Add(t));
            }
        }