// this file was generated by a tool 
{%- set schema_name = class_name | pascal -%}
{%- set list_type = "List" %}
{%- set schema = root %}

{%- macro emitclass(type, type_name) -%}
    {%- if type.type == 'object' or not type.type %}
    /// <summary>
    /// {{ type.description | default(type_name | pascal, true) }}
    /// </summary>
    public partial class {{ type_name | pascal }}
    {%- if type.allOf -%}
        {%- for allOfType in type.allOf -%}
            {%- if loop.first -%}
            {%- if allOfType['$ref'] -%}
                : {{ allOfType['$ref'] | schema_type( project_name, root) | pascal }}
            {%- endif -%}
            {%- endif -%}
        {%- endfor -%}
    {%- endif %}
    {
        /// <summary>
        /// Creates a new instance of {{ type_name | pascal }} from the provided data
        /// </summary>
        /// <param name="data">The data to use to create the new instance. 
        /// This may be a string or JsonElement or an instance of this class.</param>
        /// <returns>{{ type_name | pascal }}</returns>
        public static {{ type_name | pascal }}? FromData(object? data, string? contentType)
        {
            // generated from a JSON schema and therefore only supporting JSON
            if ( data is {{ type_name | pascal }})
            {
                return ({{ type_name | pascal }})data;
            }
            if (data is JsonElement) 
            {
                return JsonSerializer.Deserialize<{{ type_name | pascal }}>((JsonElement)data);
            }
            else if ( data is string)
            {
                return JsonSerializer.Deserialize<{{ type_name | pascal }}>((string)data);
            }
            else if (data is BinaryData)
            {
                return ((BinaryData)data).ToObjectFromJson<{{ type_name | pascal }}>();
            }
            throw new NotSupportedException("Data is not of a supported type for conversion to {{ type_name | pascal }}");
        }

        /// <summary>
        /// Serializes this object into a byte array using the JSON serializer
        /// </summary>
        public byte[] ToByteArray(string contentType) 
        {
            if ( contentType = System.Net.Mime.MediaTypeNames.Application.Json )
            {
                return JsonSerializer.SerializeToUtf8Bytes(this);
            }
            throw new NotSupportedException("Serialization to " + contentType + " is not supported");
        }

        /// <summary>
        /// Creates a deep copy of this object
        /// </summary>
        /// <returns>{{ type_name | pascal }}</returns>
        // <remarks>All data objects are cloned once before sending to trigger setter validations</remarks>
        public {{ type_name | pascal }} Clone() 
        {
            return new {{ type_name | pascal }}(){% if not type.properties %};
            {% else %}
            {
            {%- for pn, property in type.properties.items() %}   
                {%- set propertyName = pn | strip_invalid_identifier_characters | pascal %}   
                {{ propertyName }} = this.{{ propertyName }}{% if not loop.last %},{% endif %}
            {%- endfor %} 
            };
            {%- endif %}
        }
        
    {% if type.properties %}
    {% for pn, property in type.properties.items()  -%}
        {%- set propertyName = pn | strip_invalid_identifier_characters %}
        {%- set csharpType = "" -%}
        {%- if property.type == 'integer' -%}
            {%- if property.format == 'int32' -%}
                {%- set csharpType = "int" -%}
            {%- elif property.format == 'int64' -%}
                {%- set csharpType = "long" -%}
            {%- else -%}    
                {%- set csharpType = "int" -%}
            {%- endif -%}
        {%- elif property.type == 'number' -%}
            {%- if property.format == 'float' -%}
                {%- set csharpType = "float" -%}
            {%- elif property.format == 'double' -%}
                {%- set csharpType = "double" -%}
            {%- elif property.format == 'decimal' -%}
                {%- set csharpType = "decimal" -%}
            {%- else -%}
                {%- set csharpType = "double" -%}
            {%- endif -%}
        {%- elif property.type == 'string' -%}
            {%- if property.format == 'date-time' -%}
                {%- set csharpType = "DateTime" -%}
            {%- endif -%}
            {%- if property.format == 'email' -%}
                {%- set csharpType = "string" -%}
            {%- endif -%}
            {%- if property.format == 'uri' -%}
                {%- set csharpType = "Uri" -%}
            {%- endif -%}
            {%- if property.format == 'date' -%}
                {%- set csharpType = "DateTime" -%}
            {%- endif -%}
            {%- if property.format == 'time' -%}
                {%- set csharpType = "TimeSpan" -%}
            {%- endif -%}
            {%- if property.format == 'uuid' -%}
                {%- set csharpType = "Guid" -%}
            {%- endif -%}
            {%- if property.format == 'ipv4' -%}
                {%- set csharpType = "IPAddress" -%}
            {%- endif -%}
            {%- if property.format == 'ipv6' -%}
                {%- set csharpType = "IPAddress" -%}
            {%- endif -%}
            {%- if property.format == 'hostname' -%}
                {%- set csharpType = "string" -%}
            {%- endif -%}
            {%- if not property.format -%}
                {%- set csharpType = "string" -%}
            {%- endif -%}
        {%- elif property.type == 'array' -%}
            {%- if property.items.type == 'integer' -%}
                {%- if property.items.format == 'int32' or not property.items.format -%}
                    {%- set csharpType = list_type+"<int>" -%}
                {%- endif -%}
                {%- if property.items.format == 'int64' -%}
                    {%- set csharpType = list_type+"<long>" -%}
                {%- endif -%}
            {%- elif property.items.type == 'number' -%}
                {%- if property.items.format == 'float' -%}
                    {%- set csharpType = list_type+"<float>" -%}
                {%- endif -%}
                {%- if property.items.format == 'double' or not property.items.format -%}
                    {%- set csharpType = list_type+"<double>" -%}
                {%- endif -%}
                {%- if property.items.format == 'decimal' -%}
                    {%- set csharpType = list_type+"<decimal>" -%}
                {%- endif -%}
            {%- elif property.items.type == 'string' -%}
                {%- if property.items.format == 'date-time' -%}
                    {%- set csharpType = list_type+"<DateTime>" -%}
                {%- endif -%}
                {%- if property.items.format == 'email' -%}
                    {%- set csharpType = list_type+"<string>" -%}
                {%- endif -%}
                {%- if property.items.format == 'uri' -%}
                    {%- set csharpType = list_type+"<Uri>" -%}
                {%- endif -%}
                {%- if property.items.format == 'uuid' -%}
                    {%- set csharpType = list_type+"<Guid>" -%}
                {%- endif -%}
                {%- if property.items.format == 'ipv4' -%}
                    {%- set csharpType = list_type+"<IPAddress>" -%}
                {%- endif -%}
                {%- if property.items.format == 'ipv6' -%}
                    {%- set csharpType = list_type+"<IPAddress>" -%}
                {%- endif -%}
                {%- if property.items.format == 'hostname' -%}
                    {%- set csharpType = list_type+"<string>" -%}
                {%- endif -%}
                {%- if not property.items.format -%}
                    {%- set csharpType = list_type+"<string>" -%}
                {%- endif -%}
            {%- elif property.items['$ref'] -%} 
                {%- set ref = property.items['$ref'] -%}
                {%- set csharpType = list_type+"<"+(ref | schema_type( project_name, root) | pascal)+">" -%}
            {%- elif 'type' in property['items'] and property['items']['type'] == "object" and 'properties' in property['items'] -%}
                {%- set csharpType = list_type+"<"+((propertyName + "Item") | pascal)+">" -%}
                {{ emitclass( property['items'], (propertyName + "Item") | pascal) | indent }}
            {%- else -%}
                {%- set csharpType = list_type+"<object>" -%}
            {%- endif -%}
        {%- else -%}
            {%- set csharpType = "object" -%}
        {%- endif -%}
        {%- if (not property.type) or property.type == "object"  -%}
            {%- if property['$ref'] -%}
                {%- set ref = property['$ref'] -%}
                {%- set csharpType = ref | schema_type( project_name, root) | pascal -%}
            {%- elif property.properties -%}
                {%- set csharpType = (propertyName + "Item") | pascal -%}
                {{ emitclass(property, csharpType) | indent }}
            {%- endif -%}
        {%- endif -%}
        {%- if property.enum %}
        /// <summary>
        /// {{ propertyName | pascal }}Enum
        /// </summary>
        public enum {{ propertyName | pascal }}Enum
        {
            {% for value in property.enum %}
                {{ value | pascal }} = {{ loop.index - 1 }},
            {% endfor %}
        }
        
        /// <summary>
        /// {{ propertyName | pascal }}
        /// </summary>
        private {{ propertyName | pascal }}Enum {{ propertyName }} = {{ propertyName | pascal }}Enum.{{ property.enum[0] | pascal }};
        /// <summary>
        /// {{ propertyName | pascal }}
        /// </summary>
        {%- if property.description %} 
        /// <description>{{property.description}}</description> 
        {%- endif %}
        [JsonPropertyName("{{ propertyName }}")]
        public {{ propertyName | pascal }}Enum {{ propertyName | pascal }}
        {
            get
            {
                return {{ propertyName }};
            }
            set
            {
                if (!Enum.IsDefined(typeof({{ propertyName | pascal }}Enum), value))
                {
                    throw new ArgumentOutOfRangeException("{{ propertyName | pascal }}", ExceptionMessages.ValueIsInvalid);
                }
                {{ propertyName }} = value;
            }
        }
        {%- else -%}
        {%- if not (type.required and pn in type.required) -%}
        {%- set csharpType = csharpType + "?" -%}
        {%- endif %}
        private {{ csharpType }} {{ propertyName }};
        /// <summary>
        /// {{ propertyName | pascal }}
        /// </summary>
        {%- if property.description %} 
        /// <description>{{property.description}}</description> 
        {%- endif %}
        [JsonPropertyName("{{ propertyName }}")]
        public {{ csharpType }} {{ propertyName | pascal }}
        {
            get
            {
                return {{ propertyName }};
            }
            set
            {
                {%- if property.minimum -%}
                if (value < {{ property.minimum }})
                {
                    throw new ArgumentOutOfRangeException("{{ propertyName | pascal }}", string.Format(ExceptionMessages.ValueIsTooSmall, value, {{ property.minimum }}));
                }
                {%- endif -%}
                {%- if property.exclusiveMinimum -%}
                if (value <= {{ property.exclusiveMinimum }})
                {
                    throw new ArgumentOutOfRangeException("{{ propertyName | pascal }}", string.Format(ExceptionMessages.ValueIsTooSmall, value, {{ property.exclusiveMinimum }}));
                }
                {%- endif -%}
                {%- if property.maximum -%}
                if (value > {{ property.maximum }})
                {
                    throw new ArgumentOutOfRangeException("{{ propertyName | pascal }}", string.Format(ExceptionMessages.ValueIsTooBig, value, {{ property.maximum }}));
                }
                {%- endif -%}
                {%- if property.exclusiveMaximum -%}
                if (value >= {{ property.exclusiveMaximum }})
                {
                    throw new ArgumentOutOfRangeException("{{ propertyName | pascal }}", string.Format(ExceptionMessages.ValueIsTooBig, value, {{ property.exclusiveMaximum }}));
                }
                {%- endif -%}
                    {%- if property.maxLength -%}
                if (!string.IsNullOrEmpty(value) && value.ToString().Length > {{ property.maxLength }})
                {
                    throw new ArgumentOutOfRangeException("{{ propertyName | pascal }}", string.Format(ExceptionMessages.ValueIsTooLong, value, {{ property.maxLength }}));
                }
                {%- endif -%}
                {%- if property.minLength -%}
                if (string.IsNullOrEmpty(value) || value.ToString().Length < {{ property.minLength }})
                {
                    throw new ArgumentOutOfRangeException("{{ propertyName | pascal }}", string.Format(ExceptionMessages.ValueIsTooShort, value, {{ property.minLength }}));
                }
                {%- endif -%}
                {%- if property.pattern -%}
                if (!string.IsNullOrEmpty(value) && !System.Text.RegularExpressions.Regex.IsMatch(value.ToString(), RegexPatterns.{{ property.pattern | pascal }}))
                {
                    throw new ArgumentOutOfRangeException("{{ propertyName | pascal }}", ExceptionMessages.ValueIsInvalid);
                }
                {%- endif -%}
                {%- if property.format == "email" -%}
                if (!string.IsNullOrEmpty(value) && !System.Text.RegularExpressions.Regex.IsMatch(System.Text.Json.JsonSerializer.Serialize(value), RegexPatterns.Email, System.Text.RegularExpressions.RegexOptions.Singleline))
                {
                    throw new System.ArgumentException(ExceptionMessages.ValueIsNotAnEmail, "{{ propertyName | pascal }}");
                }
                {%- endif %}
                {{ propertyName }} = value;
            }
        }    
        {% endif -%}
    {%- endfor -%}
    {%- endif %}
    }
    {% endif -%}
{%- endmacro %}

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace {{ schema_name | namespace(project_name) | pascal }}
{
    {{- emitclass( schema, schema_name | strip_namespace ) }}
}


