/* **********************************************************************************
 *
 * Copyright (c) Microsoft Corporation. All rights reserved.
 *
 * This source code is subject to terms and conditions of the Shared Source License
 * for IronPython. A copy of the license can be found in the License.html file
 * at the root of this distribution. If you can not locate the Shared Source License
 * for IronPython, please send an email to ironpy@microsoft.com.
 * By using this source code in any fashion, you are agreeing to be bound by
 * the terms of the Shared Source License for IronPython.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * **********************************************************************************/

using System;
using System.Text;
using System.Reflection;

namespace IronPython.Runtime {
    static class ReflectionUtil {
        public static string DocOneInfo(MethodBase info) {
            // append custom info, if available.
            object[] attrs = info.GetCustomAttributes(typeof(DocumentationAttribute), false);
            if (attrs != null && attrs.Length > 0) {
                DocumentationAttribute doc = attrs[0] as DocumentationAttribute;
                return doc.Value;
            } else {
                return CreateAutoDoc(info);
            }
        }

        public static string CreateAutoDoc(MethodBase info) {
            StringBuilder retType = new StringBuilder();
            StringBuilder ret = new StringBuilder();

            MethodInfo mi = info as MethodInfo;
            if (mi != null) {
                retType.Append(GetPythonTypeName(mi.ReturnType));

                if (mi.Name.IndexOf('#') == -1) ret.Append(mi.Name);
                else ret.Append(mi.Name, 0, mi.Name.IndexOf('#'));
            } else {
                ret.Append("__new__");
            }
            
            // For generic methods display either type parameters (for unbound methods) or
            // type arguments (for bound ones).
            if (mi != null && mi.IsGenericMethod) {
                Type[] typePars = mi.GetGenericArguments();
                bool unbound = mi.ContainsGenericParameters;
                ret.Append("[");
                if (typePars.Length > 1)
                    ret.Append("(");

                bool insertComma = false;
                foreach (Type t in typePars) {
                    if (insertComma)
                        ret.Append(", ");
                    if (unbound)
                        ret.Append(t.Name);
                    else
                        ret.Append(GetPythonTypeName(t));
                    insertComma = true;
                }

                if (typePars.Length > 1)
                    ret.Append(")");
                ret.Append("]");
            }

            ret.Append("(");
            bool needComma = false, foundOut=false;

            foreach (ParameterInfo pi in info.GetParameters()) {
                if (pi.IsOut) {
                    if (!foundOut) {
                        retType.Insert(0, '(');
                        foundOut = true;
                    }

                    retType.Append(", ");                    
                    retType.Append(GetPythonTypeName(pi.ParameterType));

                    if (!pi.IsIn) continue;
                }

                if (needComma) ret.Append(", ");
                ret.Append(GetPythonTypeName(pi.ParameterType));
                ret.Append(" ");
                ret.Append(pi.Name);
                needComma = true;
            }
            ret.Append(")");

            if (foundOut) {
                retType.Append(')');
            }

            if (mi != null && mi.IsStatic) 
                retType.Insert(0, "static ");

            if(retType.Length != 0) retType.Append(' ');

            retType.Append(ret.ToString());

            return retType.ToString();
        }

        public static bool IsParamArray(ParameterInfo pi) {
            return pi.IsDefined(typeof(ParamArrayAttribute), false);
        }

        public static bool IsParamDict(ParameterInfo pi) {
            return pi.IsDefined(typeof(ParamDictAttribute), false);
        }

        private static string GetPythonTypeName(Type type) {
            if (type.IsByRef) {
                type = type.GetElementType();
            }

            return (string)Ops.GetDynamicTypeFromType(type).__name__;
        }


    }
}
