using FishNet.CodeGenerating.Helping.Extension;
using MonoFN.Cecil;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace FishNet.CodeGenerating.Helping
{
    internal static class Constructors
    {
        /// 
        /// Gets the first constructor that optionally has, or doesn't have parameters.
        /// 
        /// 
        /// 
        public static MethodDefinition GetFirstConstructor(this TypeReference typeRef, CodegenSession session, bool requireParameters)
        {
            return typeRef.CachedResolve(session).GetFirstConstructor(requireParameters);
        }
        /// 
        /// Gets the first constructor that optionally has, or doesn't have parameters.
        /// 
        /// 
        /// 
        public static MethodDefinition GetFirstConstructor(this TypeDefinition typeDef, bool requireParameters)
        {
            foreach (MethodDefinition methodDef in typeDef.Methods)
            {
                if (methodDef.IsConstructor && methodDef.IsPublic)
                {
                    if (requireParameters && methodDef.Parameters.Count > 0)
                        return methodDef;
                    else if (!requireParameters && methodDef.Parameters.Count == 0)
                        return methodDef;
                }
            }
            return null;
        }
        /// 
        /// Gets the first public constructor with no parameters.
        /// 
        /// 
        public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session)
        {
            return typeRef.CachedResolve(session).GetConstructor();
        }
        /// 
        /// Gets the first public constructor with no parameters.
        /// 
        /// 
        public static MethodDefinition GetConstructor(this TypeDefinition typeDef)
        {
            foreach (MethodDefinition methodDef in typeDef.Methods)
            {
                if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == 0)
                    return methodDef;
            }
            return null;
        }
        /// 
        /// Gets all constructors on typeDef.
        /// 
        /// 
        public static List GetConstructors(this TypeDefinition typeDef)
        {
            List lst = new List();
            foreach (MethodDefinition methodDef in typeDef.Methods)
            {
                if (methodDef.IsConstructor)
                    lst.Add(methodDef);
            }
            return lst;
        }
        /// 
        /// Gets constructor which has arguments.
        /// 
        /// 
        /// 
        public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, Type[] arguments)
        {
            return typeRef.CachedResolve(session).GetConstructor(arguments);
        }
        /// 
        /// Gets constructor which has arguments.
        /// 
        /// 
        /// 
        public static MethodDefinition GetConstructor(this TypeDefinition typeDef, Type[] arguments)
        {
            Type[] argsCopy = (arguments == null) ? new Type[0] : arguments;
            foreach (MethodDefinition methodDef in typeDef.Methods)
            {
                if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == argsCopy.Length)
                {
                    bool match = true;
                    for (int i = 0; i < argsCopy.Length; i++)
                    {
                        if (methodDef.Parameters[0].ParameterType.FullName != argsCopy[i].FullName)
                        {
                            match = false;
                            break;
                        }
                    }
                    if (match)
                        return methodDef;
                }
            }
            return null;
        }
        /// 
        /// Gets constructor which has arguments.
        /// 
        /// 
        /// 
        public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, TypeReference[] arguments)
        {
            return typeRef.CachedResolve(session).GetConstructor(arguments);
        }
        /// 
        /// Gets constructor which has arguments.
        /// 
        /// 
        /// 
        public static MethodDefinition GetConstructor(this TypeDefinition typeDef, TypeReference[] arguments)
        {
            TypeReference[] argsCopy = (arguments == null) ? new TypeReference[0] : arguments;
            foreach (MethodDefinition methodDef in typeDef.Methods)
            {
                if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == argsCopy.Length)
                {
                    bool match = true;
                    for (int i = 0; i < argsCopy.Length; i++)
                    {
                        if (methodDef.Parameters[0].ParameterType.FullName != argsCopy[i].FullName)
                        {
                            match = false;
                            break;
                        }
                    }
                    if (match)
                        return methodDef;
                }
            }
            return null;
        }
        /// 
        /// Resolves the constructor with parameterCount for typeRef.
        /// 
        /// 
        /// 
        public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, int parameterCount)
        {
            return typeRef.CachedResolve(session).GetConstructor(parameterCount);
        }
        /// 
        /// Resolves the constructor with parameterCount for typeRef.
        /// 
        /// 
        /// 
        public static MethodDefinition GetConstructor(this TypeDefinition typeDef, int parameterCount)
        {
            foreach (MethodDefinition methodDef in typeDef.Methods)
            {
                if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == parameterCount)
                    return methodDef;
            }
            return null;
        }
    }
}