// Returns the html for all hidden inputs associated with the model
        private static string HiddenInput(ModelMetadata metadata, string propertyName, bool includeDefault)
        {
            StringBuilder html = new StringBuilder();

            if (metadata.ModelType.IsArray && metadata.Model != null)
            {
                // Primarily for database time stamps, this need to called before checking IsComplexType
                // otherwise an endless loop is created
                html.Append(HiddenInput(propertyName, Convert.ToBase64String(metadata.Model as byte[])));
            }
            else if (metadata.IsComplexType)
            {
                foreach (ModelMetadata propertyMetadata in metadata.Properties)
                {
                    if (propertyMetadata.IsCollection() && !propertyMetadata.ModelType.IsArray)
                    {
                        // This would just render the Count and Capacity property of List<T>
                        continue;
                    }
                    if (propertyMetadata.Model == null && propertyMetadata.ModelType != typeof(string) && !propertyMetadata.IsRequired)
                    {
                        // Ignore complex types that are null and do not have the RequiredAttribute
                        continue;
                    }
                    // Recursive call to render a hidden input for the property
                    string prefix = null;
                    if (String.IsNullOrEmpty(propertyName))
                    {
                        prefix = propertyMetadata.PropertyName;
                    }
                    else
                    {
                        prefix = string.Format("{0}.{1}", propertyName, propertyMetadata.PropertyName);
                    }
                    html.Append(HiddenInput(propertyMetadata, prefix, true));
                }
            }
            else
            {
                object value = metadata.Model;
                if (value == null && includeDefault)
                {
                    value = metadata.DefaultValue();
                }
                html.Append(HiddenInput(propertyName, value));
            }
            return(html.ToString());
        }
        /// <summary>
        /// Returns the html for a numeric input that formats the display of values.
        /// </summary>
        /// <param name="metaData">
        /// The metadata of the property.
        /// </param>
        /// <param name="fieldName">
        /// The fully qualified name of the property.
        /// </param>
        /// <param name="attributes">
        /// The validation attributes to rendered in the input.
        /// </param>
        /// <param name="includeID">
        /// A value indicating the the 'id' attribute should be rendered for the input.
        /// </param>
        private static string NumericInput(ModelMetadata metaData, string fieldName,
                                           IDictionary <string, object> attributes, bool includeID)
        {
            string        defaultFormat = "{0:N}";
            StringBuilder html          = new StringBuilder();
            // Build formatted display text
            TagBuilder display = new TagBuilder("div");

            // Add essential styles
            display.MergeAttribute("style", "position:absolute;");
            // Add class names
            display.AddCssClass("numeric-text");
            if (Convert.ToDouble(metaData.Model) < 0)
            {
                display.AddCssClass("negative");
            }
            if (metaData.IsCurrency())
            {
                defaultFormat = "{0:C}";
                display.AddCssClass("currency");
            }
            else if (metaData.IsPercent())
            {
                defaultFormat = "{0:P}";
                display.AddCssClass("percent");
            }
            else
            {
                display.AddCssClass("number");
            }
            if (Type.GetTypeCode(metaData.ModelType) == TypeCode.Int32)
            {
                defaultFormat = "{0:N0}";
            }
            // Format text
            defaultFormat     = metaData.DisplayFormatString ?? defaultFormat;
            display.InnerHtml = string.Format(defaultFormat, metaData.Model ?? metaData.DefaultValue());

            // TODO: What about nullable types
            //metaData.NullDisplayText;

            html.Append(display.ToString());
            // Build input
            TagBuilder input = new TagBuilder("input");

            input.AddCssClass("numeric-input");
            input.MergeAttribute("autocomplete", "off");
            input.MergeAttribute("type", "text");
            if (includeID)
            {
                input.MergeAttribute("id", HtmlHelper.GenerateIdFromName(fieldName));
            }
            input.MergeAttribute("name", fieldName);
            input.MergeAttribute("value", string.Format("{0}", metaData.Model ?? metaData.DefaultValue()));
            // Remove the data-val-number attribute (the client script ensures its a number and jquery
            // validation generates an error message if the first character is a decimal point which
            // disappears as soon as the next digit is entered - PITA when entering percentage values)
            // TODO: Still happens if a Range attribute is added!
            if (attributes != null && attributes.ContainsKey("data-val-number"))
            {
                attributes.Remove("data-val-number");
            }
            input.MergeAttributes(attributes);
            html.Append(input.ToString());
            // Build container
            TagBuilder container = new TagBuilder("div");

            container.AddCssClass("numeric-container");
            // Add data attributes for use by client script
            if (metaData.IsCurrency())
            {
                //container.MergeAttributes(GetCurrencyDataAttributes(metaData.DisplayFormatString));
                container.MergeAttributes(GetCurrencyDataAttributes(defaultFormat));
            }
            else if (metaData.IsPercent())
            {
                //container.MergeAttributes(GetPercentDataAttributes(metaData.DisplayFormatString));
                container.MergeAttributes(GetPercentDataAttributes(defaultFormat));
            }
            else
            {
                //container.MergeAttributes(GetNumberDataAttributes(metaData.DisplayFormatString));
                container.MergeAttributes(GetNumberDataAttributes(defaultFormat));
            }
            // Add essential styles
            container.MergeAttribute("style", "position:relative;margin:0;padding:0;");
            container.InnerHtml = html.ToString();
            // Return the html
            return(container.ToString());
        }