﻿using System;
using System.Reflection;
using Vidyano.Service;

namespace Vidyano.Extensions
{
    /// <summary>
    /// Exposes Reflection related helper methods to Vidyano JavaScript code (http://www.vidyano.com/Documentation/javascript)
    /// </summary>
    [ExposeToJavaScript]
    public static partial class Reflection
    {
        #region Methods

        /// <summary>
        /// Can be used in JavaScript to create a new instance.
        /// <code>
        /// var client = Reflection.createInstance("System.Net.WebClient");
        /// </code>
        /// </summary>
        public static object CreateInstance(string typeName)
        {
            return Activator.CreateInstance(GetType(typeName));
        }

        /// <summary>
        /// <code>
        /// var type = Reflection.getType("System.Threading.Thread");
        /// </code>
        /// </summary>
        public static Type GetType(string typeName)
        {
            return Type.GetType(typeName, false);
        }

        public static FieldInfo GetField(object instance, string name)
        {
            return instance != null ? instance.GetType().GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) : null;
        }

        public static object GetFieldValue(object instance, string name)
        {
            var fieldInfo = GetField(instance, name);
            return fieldInfo != null ? fieldInfo.GetValue(instance) : null;
        }

        /// <summary>
        /// <code>
        /// var lengthProperty = Reflection.getProperty("String", "Length");
        /// </code>
        /// </summary>
        public static PropertyInfo GetProperty(object instance, string name)
        {
            return instance != null ? instance.GetType().GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) : null;
        }

        /// <summary>
        /// <code>
        /// var length = Reflection.getPropertyValue("String", "Length");
        /// </code>
        /// </summary>
        public static object GetPropertyValue(object instance, string name)
        {
            var propertyInfo = GetProperty(instance, name);
            return propertyInfo != null ? propertyInfo.GetValue(instance, null) : null;
        }
        
        public static object InvokeMethod(object instance, string name, params object[] arguments)
        {
            var methodInfo = instance != null ? instance.GetType().GetMethod(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) : null;
            return methodInfo != null ? methodInfo.Invoke(instance, arguments) : null;
        }

        /// <summary>
        /// <code>
        /// var asm = Reflection.loadAssembly("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken= b77a5c561934e089");
        /// </code>
        /// </summary>
        public static Assembly LoadAssembly(string assemblyString)
        {
            return Assembly.Load(assemblyString);
        }

        /// <summary>
        /// <code>
        /// var asm = Reflection.loadAssemblyFile("c:\\temp\\assembly.dll");
        /// </code>
        /// </summary>
        public static Assembly LoadAssemblyFile(string path)
        {
            return Assembly.LoadFile(path);
        }
        
        #endregion
    }
}