using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace Hydra.Framework
{
    public class DumpObj
    {
        /// <summary>
        /// Initialises a new instance of the <see cref="T:DumpObj"/> class.
        /// </summary>
        protected DumpObj()
        {
        }

        /// <summary>
        /// Dumps the object.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <returns>string representation of the object</returns>
        public static string DumpObject(object obj)
        {
            return DumpObj.DumpObject(obj, -1);
        }

        /// <summary>
        /// Dumps the object.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <param name="MaxLevel">The max level.</param>
        /// <returns>string representation of the object</returns>
        public static string DumpObject(object obj, int MaxLevel)
        {
            StringBuilder sb;

            sb = new StringBuilder(10000);
            if (obj == null)
            {
                sb.Append("Nothing");
            }
            else
            {
                DumpObj.PrivDump(sb, obj, "[ObjectToDump]", 0, MaxLevel);
            }

            return sb.ToString();
        }

        /// <summary>
        /// Gets the field value.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <param name="fieldName">StateName of the field.</param>
        /// <returns>The field value if known otherwise null</returns>
        public static object GetFieldValue(object obj, string fieldName)
        {
            FieldInfo fi;
            Type t;

            t = obj.GetType();
            fi = t.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            return (fi == null) ? null : fi.GetValue(obj);
        }

        /// <summary>
        /// Privs the dump.
        /// </summary>
        /// <param name="sb">The sb.</param>
        /// <param name="obj">The obj.</param>
        /// <param name="objName">StateName of the obj.</param>
        /// <param name="level">The level.</param>
        /// <param name="MaxLevel">The max level.</param>
        protected static void PrivDump(StringBuilder sb, object obj, string objName, int level, int MaxLevel)
        {

            if (obj == null)
                return;
            if (MaxLevel >= 0 && level >= MaxLevel)
                return;

            string padstr;
            padstr = "";
            for (int i = 0; i < level; i++)
                padstr += (i < level - 1) ? "|" : "+";

            string str;
            string[] strarr;
            Type t;
            t = obj.GetType();
            strarr = new String[7];
            strarr[0] = padstr;
            strarr[1] = objName;
            strarr[2] = " AS ";
            strarr[3] = t.FullName;
            strarr[4] = " = ";
            strarr[5] = obj.ToString();
            strarr[6] = "\r\n";
            sb.Append(String.Concat(strarr));

            if (obj.GetType().BaseType == typeof(ValueType))
                return;

            DumpObj.DumpType(padstr, sb, obj, level, t, MaxLevel);
            Type bt;
            bt = t.BaseType;
            if (bt != null)
            {
                while (!(bt == typeof(object)))
                {
                    str = bt.FullName;
                    sb.Append(padstr + "(" + str + ")\r\n");
                    DumpObj.DumpType(padstr, sb, obj, level, bt, MaxLevel);
                    bt = bt.BaseType;
                    if (bt == null)
                        break;
                } while (bt != typeof(object)) ;
            }
        }

        /// <summary>
        /// Dumps the type.
        /// </summary>
        /// <param name="InitialStr">The initial STR.</param>
        /// <param name="sb">The sb.</param>
        /// <param name="obj">The obj.</param>
        /// <param name="level">The level.</param>
        /// <param name="t">The t.</param>
        /// <param name="maxlevel">The maxlevel.</param>
        protected static void DumpType(string InitialStr, StringBuilder sb, object obj, int level, System.Type t, int maxlevel)
        {
            FieldInfo[] fi;
            object[] arl;
            int i;

            fi = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            if (t == typeof(System.Delegate)) return;

            foreach (FieldInfo f in fi)
                PrivDump(sb, f.GetValue(obj), f.Name, level + 1, maxlevel);

            if (obj is System.Array)
            {
                try
                {
                    arl = (object[])obj;
                    for (i = 0; i < arl.GetLength(0); i++)
                        PrivDump(sb, arl[i], "[" + i + "]", level + 1, maxlevel);
                }
                catch (Exception) { }
            }
        }
    }
}
