/*
Copyright 2005 Danal Technology Inc.
All Rights Reserved

dsullivan@danal.com

This example is for tutorial purposes only. It may
not be used for any other purpose.
*/


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Nmo;
using System.Reflection;
namespace DynamicSMOTree
{
    abstract public class SmoNode : TreeNode
    {

        static protected SmoNode MakeSmoNode(Object @object)
        {

            return MakeSmoNode(@object, String.Empty);
        }
        static protected SmoNode MakeSmoNode(Object @object, String name)
        {
            
            if (@object.GetType().IsSubclassOf(typeof(SqlSmoObject)))
            {
                ((SqlSmoObject)@object).Initialize();
                SmoNode sn = new SmoObjectNode((SqlSmoObject)@object, name);
                sn.ToolTipText = ((SqlSmoObject)@object).Urn.Value;
                return sn;
            }
            if (@object.GetType().IsSubclassOf(typeof(AbstractCollectionBase)))
            {
                return new SmoCollectionNode((SmoCollectionBase)@object, name);
            }
            return null;
        }
        public void Initialize()
        {
            if (@object is SqlSmoObject)
            {
                SqlSmoObject sso = @object as SqlSmoObject;
                sso.Initialize();
            }
        }
       
        public Urn Urn
        {
            get
            {
                SqlSmoObject smo = @object as SqlSmoObject;
                if (smo != null)
                {
                    return smo.Urn;
                }
                else
                {
                    return String.Empty;
                }
            }
        }
        protected Boolean childrenAdded = false;
        protected Object @object;
        internal SmoNode(Object @object)
        {
            
            this.@object = @object;
        }
        internal void AddValues(PropertyInfo propertyInfo, Object @object)
        {
            AddValues(propertyInfo, @object, this as TreeNode);
        }
        internal void AddValues(FieldInfo fieldInfo, Object @object)
        {
            AddValues(fieldInfo, @object, this as TreeNode);
        }
        static String[] SmoNamespaces =
            new String[] {
            "Microsoft.SqlServer.Management.Smo",
            "Microsoft.SqlServer.Smo.Management",
            "Microsoft.SqlServer.Common"
            };
        internal void AddConfiguration(TreeNode parent, Configuration config)
        {
            foreach (PropertyInfo pi in typeof(Configuration).GetProperties())
            {
                if (pi.PropertyType == typeof(ConfigProperty))
                {
                    TreeNode cPropTreeNode = parent.Nodes.Add(pi.Name + ":");
                    ConfigProperty cProp = (ConfigProperty)pi.GetValue(config, new object[] { });
                    foreach (PropertyInfo cpi in typeof(ConfigProperty).GetProperties())
                    {
                        String value = cpi.Name + ": ";
                        try
                        {
                            value += cpi.GetValue(cProp, new object[] { }).ToString();
                        }
                        catch
                        {
                        }
                        cPropTreeNode.Nodes.Add(value);
                    }
                }
            }
        }
        internal void AddValues(PropertyInfo propertyInfo, Object @object, TreeNode tn)
        {
            // add string and value types to tree
            if (@object != null)
            {
                Type propertyType = propertyInfo.PropertyType;
                if (propertyType == typeof(Configuration))
                {
                    Configuration config = (Configuration)propertyInfo.GetValue(@object, new object[] { });
                    TreeNode childNode = tn.Nodes.Add(propertyInfo.Name + ":");
                    AddConfiguration(childNode, config);
                    return;
                }
                else
                    if ((propertyType.IsSubclassOf(typeof(ValueType)))
                    || (propertyType == typeof(String)))
                    {
                        String value = "???";
                        try
                        {
                            Object propObject = propertyInfo.GetValue(@object, new object[] { });
                            value = propObject.ToString();
                        }
                        catch { }
                        tn.Nodes.Add(propertyInfo.Name + ": " + value);
                    }
                    else
                    {
                        if (!childrenAdded)
                        {
                            if (Array.Exists(SmoNamespaces, delegate(String @namespace)
                            {
                                return @namespace == propertyInfo.PropertyType.Namespace;
                            }
                                ))
                            {
                                Object propObject = null;
                                {
                                    try
                                    {
                                        propObject = propertyInfo.GetValue(@object, new object[] { });

                                    }
                                    catch
                                    {
                                        return;
                                    }
                                    if (propObject != null)
                                    {
                                        TreeNode childNode = tn.Nodes.Add(propertyInfo.Name + ":");

                                        foreach (FieldInfo fi in propObject.GetType().GetFields())
                                        {
                                            try
                                            {
                                                Object childObject = fi.GetValue(propObject);
                                                AddValues(fi, childObject, childNode);
                                            }
                                            catch { }
                                        }
                                        foreach (PropertyInfo pi in propObject.GetType().GetProperties())
                                        {
                                            try
                                            {
                                                Object childObject = pi.GetValue(propObject, new object[] { });
                                                AddValues(pi, childObject, childNode);
                                            }
                                            catch { }
                                        }
                                    }
                                }

                            }
                        }
                        childrenAdded = true;
                    }
            }
        }

        internal void AddValues(FieldInfo fieldInfo, Object @object, TreeNode tn)
        {
            // add string and value types to tree
            if (@object != null)
            {
                Type fieldType = fieldInfo.FieldType;
                if ((fieldType.IsSubclassOf(typeof(ValueType)))
                    || (fieldType.IsSubclassOf(typeof(String))))
                {
                    String value = "???";
                    try
                    {
                        Object fieldObject = fieldInfo.GetValue(@object);
                        value = fieldObject.ToString();
                    }
                    catch { }
                    tn.Nodes.Add(fieldInfo.Name + ": " + value);
                }
                else
                {
                    if (!childrenAdded)
                    {
                        if (Array.Exists(SmoNamespaces, delegate(String @namespace)
                        {
                            return @namespace == fieldInfo.FieldType.Namespace;
                        }
                            ))
                        {
                            TreeNode childNode = tn.Nodes.Add(fieldInfo.Name + ":");
                            Object fieldObject = null;
                            if (fieldType == typeof(Configuration))
                            {
                                Configuration config = (Configuration)fieldInfo.GetValue(@object);
                                AddConfiguration(childNode, config);
                            }
                            else
                            {
                                try
                                {
                                    fieldObject = fieldInfo.GetValue(@object);

                                }
                                catch
                                {
                                    return;
                                }
                                if (fieldObject != null)
                                {

                                    foreach (FieldInfo fi in fieldObject.GetType().GetFields())
                                    {
                                        try
                                        {
                                            Object childObject = fi.GetValue(fieldObject);
                                            AddValues(fi, childObject, childNode);
                                        }
                                        catch { }
                                    }
                                }
                                    foreach (PropertyInfo pi in fieldObject.GetType().GetProperties())
                                    {
                                        try
                                        {
                                            Object childObject = pi.GetValue(fieldObject, new object[] { });
                                            AddValues(pi, childObject, childNode);
                                        }
                                        catch { }
                                    }
                                }
                            }
                        }
                    }
                }
                childrenAdded = true;
            }
        
        
        
        static String[] skipProperties = new string[] 
        { "Parent",
            "Urn",
            "Properties", 
            "Events" };
        internal void AddChildren()
        {
            if ((@object != null) && !childrenAdded)
            {
                TreeNode tn = (TreeNode)this;
                Type type = @object.GetType();
                if (type.IsSubclassOf(typeof(SmoCollectionBase)))
                {
                    // don't add children for Notification Services instance
                    // 'till its fixed
                    if (type == typeof(InstanceCollection))
                    {
                        return;
                    }
                    SmoCollectionBase collection = (SmoCollectionBase)@object;
                    foreach (Object collectionObject in collection)
                    {
                        SmoNode snode;
                        tn.Nodes.Add(snode = MakeSmoNode(collectionObject));
                    }
                }
                else
                {
                    foreach (MemberInfo mi in type.GetMembers())
                    {
                        PropertyInfo pi = mi as PropertyInfo;
                        if(pi != null)
                        {
                            if (Array.Exists(skipProperties,
                                delegate(String name)
                                {
                                    return pi.Name == name;
                                }))
                            {
                                continue;
                            }
                            Type propertyType = pi.PropertyType;
                            if (propertyType.IsSubclassOf(typeof(SqlSmoObject))
                                 || propertyType.IsSubclassOf(typeof(SmoCollectionBase)))
                            {
                                Object propObject = pi.GetValue(this.@object, new object[] { });
                                if (propObject != null)
                                {
                                    SmoNode snode;
                                    tn.Nodes.Add(snode = MakeSmoNode(propObject, pi.Name));
                                }
                            }
                            else
                            {
                                AddValues(pi, @object);
                            }
                            continue;
                        }
                        FieldInfo fi = mi as FieldInfo;
                        if (fi != null)
                        {
                            Type fieldType = fi.FieldType; ;
                            if (fieldType.IsSubclassOf(typeof(SqlSmoObject))
                                 || fieldType.IsSubclassOf(typeof(SmoCollectionBase)))
                            {
                                Object propObject = fi.GetValue(this.@object);
                                if (propObject != null)
                                {
                                    SmoNode snode;
                                    tn.Nodes.Add(snode = MakeSmoNode(propObject, fi.Name));
                                }
                            }
                            else
                            {
                                AddValues(fi, @object);
                            }
                            continue;
                        }
                    }
                }
                childrenAdded = true;
            }
        }
    }
    public class SmoObjectNode : SmoNode
    {
        public SmoObjectNode(SqlSmoObject smoObject, String name)
            : base(smoObject)
        {
            int xbLength;
            XPathExpressionBlock xb = smoObject.Urn.XPathExpression[(xbLength = smoObject.Urn.XPathExpression.Length) - 1];
            String pat = (xbLength == 1 ? "" : "/" )+ xb.Name;
            String u = smoObject.Urn.Value;
            Text = "\"" + smoObject.Urn.Value.Substring(smoObject.Urn.Value.LastIndexOf(pat)) + "\"";
            if (name != String.Empty)
            {
                Text += " (" + name + ")";               
            }
        }
        public override string ToString()
        {
            return ((SqlSmoObject)@object).Urn.Value;
        }
    }
    public class SmoCollectionNode : SmoNode
    {
        public SmoCollectionNode(SmoCollectionBase smoCollection, String name)
            : base(smoCollection)
        {
            Text = smoCollection.GetType().Name;
            if (name != String.Empty)
            {
                Text += " (" + name + ")";
            }
        }
        public override string ToString()
        {
            return Text;
        }
    }
}
