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

namespace ConverterSamples
{
   class Common
   {
      /// <summary>
      /// Dumps a complex object's value to string
      /// This class is a lot simpler than ObjectDumper but
      /// is enough for dumping VMware data objects
      /// </summary>
      private class Dumper
      {
         private StringBuilder _res;


         public Dumper(Object obj)
         {
            Debug.Assert(obj != null);

            _res = new StringBuilder();

            DumpImpl(obj, obj.GetType().Name, String.Empty);
         }

         public override String ToString()
         {
            return _res.ToString();
         }

         private void
         DumpImpl(object obj, String propName, String indent)
         {
            if (obj == null) {
               _res.AppendFormat("{0}{1}: <unspecified>\n", indent, propName);
               return;
            }

            Type t = obj.GetType();

            if (t.IsPrimitive || t.IsEnum || t == typeof(String) || t == typeof(DateTime)) {
               _res.AppendFormat("{0}{1}: {2}\n", indent, propName, obj.ToString());
               return;
            }

            // Short notation for MoRefs
            if (obj is ManagedObjectReference) {
               ManagedObjectReference moRef = (ManagedObjectReference)obj;
               _res.AppendFormat("{0}{1}: '{2}:{3}'\n",
                                 indent, propName, moRef.type, moRef.Value);
               return;
            }

            String newIndent = indent + "\t";

            if (obj is Array) {
               Array a = obj as Array;

               for (int i = 0; i < a.Length; ++i) {
                  _res.AppendFormat("{0}{1}:\n", indent, propName);
                  String arrayPropName = String.Format("#{0}", i);
                  DumpImpl(a.GetValue(i), arrayPropName, newIndent);
               }
            } else {
               PropertyInfo[] props = t.GetProperties(BindingFlags.Instance |
                                                      BindingFlags.GetProperty |
                                                      BindingFlags.Public);
               _res.AppendFormat("{0}{1}:\n", indent, propName);

               foreach (PropertyInfo prop in props) {
                  if (prop.CanRead) {
                     Object newO = prop.GetValue(obj, null);
                     DumpImpl(newO, prop.Name, newIndent);
                  }
               }
            }
         }
      }



      /// <summary>
      /// Dump an object to string.
      /// The object should be a VMware data object
      /// </summary>
      /// <param name="o">The object to dump</param>
      /// <returns>The string result</returns>
      public static String
      Dump(Object o)
      {
         Dumper dumper = new Dumper(o);

         return dumper.ToString();
      }

      /// <summary>
      /// Extracts the SSL thumbprint from a location object
      /// </summary>
      /// <param name="location">The location to probe</param>
      /// <returns>The thumbprint</returns>
      public static String GetThumbprint(Object location)
      {
         Debug.Assert(location != null);

         if (location is ConverterComputerSpecLiveComputerLocation) {
            // Physical source
            return ((ConverterComputerSpecLiveComputerLocation)location).sslThumbprint;
         } else if (location is ConverterComputerSpecManagedVmLocation) {
            // Managed source
            return ((ConverterComputerSpecManagedVmLocation)location).vimConnect.sslThumbprint;
         } else if (location is ConverterComputerSpecHyperVComputerLocation) {
            // Hyper-V source
            return ((ConverterComputerSpecHyperVComputerLocation)location).sslThumbprint;
         } else if (location is ConverterTargetVmSpecManagedVmLocation) {
            // Managed target
            return ((ConverterTargetVmSpecManagedVmLocation)location).vimConnect.sslThumbprint;
         } else if (location is ConverterComputerSpecHostedVmLocation ||
                    location is ConverterTargetVmSpecHostedVmLocation) {
            // Hosted source or hosted target - no thumbprint
            return null;
         } else {
            Debug.Fail("Unexpected location type");
            return null;
         }
      }
   }
}
