<commit_before>﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;

namespace EasyRpc.AspNetCore.Documentation
{
    /// <summary>
    /// Service that generates OpenApiSchema objects based on Type
    /// </summary>
    public interface IOpenApiSchemaGenerator
    {
        /// <summary>
        /// Get OpenApiSchema for type
        /// </summary>
        /// <param name="objectType"></param>
        /// <returns></returns>
        OpenApiSchema GetSchemaType(Type objectType);

        /// <summary>
        /// Populate component 
        /// </summary>
        /// <param name="document"></param>
        void PopulateSchemaComponent(OpenApiDocument document);
    }

    public class OpenApiSchemaGenerator : IOpenApiSchemaGenerator
    {
        private int _unknownCount;
        private ConcurrentDictionary<string, OpenApiSchema> _knownComponents;
        private ConcurrentDictionary<Type, string> _referenceNames;
        private ConcurrentDictionary<string, Type> _nameMap;
        private ISimpleOpenApiTypeMapper _simpleOpenApiTypeMapper;

        public OpenApiSchemaGenerator(ISimpleOpenApiTypeMapper simpleOpenApiTypeMapper)
        {
            _simpleOpenApiTypeMapper = simpleOpenApiTypeMapper;

            _knownComponents = new ConcurrentDictionary<string, OpenApiSchema>();
            _referenceNames = new ConcurrentDictionary<Type, string>();
            _nameMap = new ConcurrentDictionary<string, Type>();
        }

        public OpenApiSchema GetSchemaType(Type objectType)
        {
            if (objectType.IsArray)
            {
                var elementSchema = GetSchemaType(objectType.GetElementType());
                
                return new OpenApiSchema
                {
                    Type = "array",
                    Items = elementSchema
                };
            }

            if (objectType != typeof(string) &&
                typeof(IEnumerable).IsAssignableFrom(objectType))
            {
                var interfaces = objectType.GetInterfaces();

                var enumerableInterface = interfaces.FirstOrDefault(i =>
                    i.IsConstructedGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));

                if (enumerableInterface != null)
                {
                    var elementSchema = GetSchemaType(enumerableInterface.GenericTypeArguments[0]);
                    
                    return new OpenApiSchema
                    {
                        Type = "array",
                        Items = elementSchema
                    };
                }
            }

            var schema = _simpleOpenApiTypeMapper.MapSimpleType(objectType);

            if (schema != null)
            {
                return schema;
            }

            if (_referenceNames.TryGetValue(objectType, out var referenceName))
            {
                return new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = referenceName } };
            }

            referenceName = GenerateReferenceName(objectType);

            if (objectType.IsEnum)
            {
                ProcessEnumTypeForComponent(referenceName, objectType);
            }
            else
            {
                ProcessTypeForComponent(referenceName, objectType);
            }

            return new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = referenceName } };
        }

        private void ProcessEnumTypeForComponent(string referenceName, Type objectType)
        {
            var schemaInstance = new OpenApiSchema { Type = "integer" };

            foreach (var value in Enum.GetValues(objectType))
            {
                schemaInstance.Enum.Add(new OpenApiInteger((int)value));
            }

            _knownComponents[referenceName] = schemaInstance;
        }

        private void ProcessTypeForComponent(string referenceName, Type objectType)
        {
            var properties = new Dictionary<string, OpenApiSchema>();
            var schemaInstance = new OpenApiSchema { Type = "object", Properties = properties };

            foreach (var propertyInfo in objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                var propertyTypeSchema = GetSchemaType(propertyInfo.PropertyType);

                properties[CasePropertyName(propertyInfo.Name)] = propertyTypeSchema;
            }

            _knownComponents[referenceName] = schemaInstance;
        }

        protected virtual string CasePropertyName(string propertyName)
        {
            if (propertyName.Length == 1)<commit_msg>fixing enum documentation bug when not int value<commit_after>﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;

namespace EasyRpc.AspNetCore.Documentation
{
    /// <summary>
    /// Service that generates OpenApiSchema objects based on Type
    /// </summary>
    public interface IOpenApiSchemaGenerator
    {
        /// <summary>
        /// Get OpenApiSchema for type
        /// </summary>
        /// <param name="objectType"></param>
        /// <returns></returns>
        OpenApiSchema GetSchemaType(Type objectType);

        /// <summary>
        /// Populate component 
        /// </summary>
        /// <param name="document"></param>
        void PopulateSchemaComponent(OpenApiDocument document);
    }

    public class OpenApiSchemaGenerator : IOpenApiSchemaGenerator
    {
        private int _unknownCount;
        private ConcurrentDictionary<string, OpenApiSchema> _knownComponents;
        private ConcurrentDictionary<Type, string> _referenceNames;
        private ConcurrentDictionary<string, Type> _nameMap;
        private ISimpleOpenApiTypeMapper _simpleOpenApiTypeMapper;

        public OpenApiSchemaGenerator(ISimpleOpenApiTypeMapper simpleOpenApiTypeMapper)
        {
            _simpleOpenApiTypeMapper = simpleOpenApiTypeMapper;

            _knownComponents = new ConcurrentDictionary<string, OpenApiSchema>();
            _referenceNames = new ConcurrentDictionary<Type, string>();
            _nameMap = new ConcurrentDictionary<string, Type>();
        }

        public OpenApiSchema GetSchemaType(Type objectType)
        {
            if (objectType.IsArray)
            {
                var elementSchema = GetSchemaType(objectType.GetElementType());
                
                return new OpenApiSchema
                {
                    Type = "array",
                    Items = elementSchema
                };
            }

            if (objectType != typeof(string) &&
                typeof(IEnumerable).IsAssignableFrom(objectType))
            {
                var interfaces = objectType.GetInterfaces();

                var enumerableInterface = interfaces.FirstOrDefault(i =>
                    i.IsConstructedGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));

                if (enumerableInterface != null)
                {
                    var elementSchema = GetSchemaType(enumerableInterface.GenericTypeArguments[0]);
                    
                    return new OpenApiSchema
                    {
                        Type = "array",
                        Items = elementSchema
                    };
                }
            }

            var schema = _simpleOpenApiTypeMapper.MapSimpleType(objectType);

            if (schema != null)
            {
                return schema;
            }

            if (_referenceNames.TryGetValue(objectType, out var referenceName))
            {
                return new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = referenceName } };
            }

            referenceName = GenerateReferenceName(objectType);

            if (objectType.IsEnum)
            {
                ProcessEnumTypeForComponent(referenceName, objectType);
            }
            else
            {
                ProcessTypeForComponent(referenceName, objectType);
            }

            return new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = referenceName } };
        }

        private void ProcessEnumTypeForComponent(string referenceName, Type objectType)
        {
            var schemaInstance = new OpenApiSchema { Type = "integer" };

            foreach (var value in Enum.GetValues(objectType))
            {
                if (value is int intValue)
                {
                    schemaInstance.Enum.Add(new OpenApiInteger(intValue));
                }
                else
                {
                    intValue = (int)Convert.ChangeType(value, typeof(int));

                    schemaInstance.Enum.Add(new OpenApiInteger(intValue));
                }
            }

            _knownComponents[referenceName] = schemaInstance;
        }

        private void ProcessTypeForComponent(string referenceName, Type objectType)
        {
            var properties = new Dictionary<string, OpenApiSchema>();
            var schemaInstance = new OpenApiSchema { Type = "object", Properties = properties };

            foreach (var propertyInfo in objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                var propertyTypeSchema = GetSchemaType(propertyInfo.PropertyType);

                properties[CasePropertyName(propertyInfo.Name)] = propertyTypeSchema;
            }

            _knownComponents[referenceName] = schemaInstance;
        }

        protected virtual string CasePropertyName(string propertyName)
        {
            if (propertyName.Length == 1)
{'fraction_non_alphanumeric': 0.078269517652909, 'fraction_numerical': 0.00039781203381402286, 'mean_word_length': 1.8913168487636574, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7319933', 'n_tokens_mistral': 2336, 'n_tokens_neox': 2213, 'n_words': 497}