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

namespace RDNZLUtil
{
    /// <summary>
    ///  An utility class with static methods for RDNZL.
    /// </summary>
    public class RDNZLUtil
    {
    
    }

    /// <summary>
    ///  The ResolverHelper class can be used to add additional
    ///  paths to search for assemblies in the Load context. It uses 
    ///  the AppDomains AssemblyResolveEvent, which is not recommended 
    ///  by Microsoft.
    /// 
    ///  In theory, this could be done inside RDNZL, but at least for ACL7
    ///  (2007-04-26) the application crashes when returning the freshly 
    ///  loaded assembly to the AppDomain that fired the event.
    /// 
    ///  An additional trick would here be to not use LoadFile, but instead
    ///  load the raw bytes of the assembly and use mydomain.Load(bytes) instead.
    ///  This avoids having the file locked by the runtime. 
    /// 
    /// 
    /// </summary>
    public class ResolverHelper
    {
        private ResolveEventHandler resolver;
        private AppDomain mydomain;

        /// <summary>
        /// The list of additional paths to search for a given assembly.
        /// </summary>
        public List<String> AdditionalPaths = new List<String>();

        /// <summary>
        /// Add a directory path to the list of AdditionalPaths in which to search for assemblies
        /// </summary>
        /// <param name="newpath">A directory path</param>
        public void add_AdditionalPaths(String newpath)
        {
            if (System.IO.Directory.Exists(newpath))
                AdditionalPaths.Add(newpath);
            else throw new System.IO.DirectoryNotFoundException("Can't add non-existing directory to the ResolverHelper: " + newpath);
        }

        /// <summary>
        /// Remove a directory path from the list of AdditionalPaths in which to search for assemblies
        /// </summary>
        /// <param name="boguspath">A directory path</param>
        public void remove_AdditionalPaths(String boguspath)
        {
            AdditionalPaths.Remove(boguspath);
        }

        /// <summary>
        /// Create a ResolverHelper and add its resolver delegate to the AppDomains AssemblyResolveEvent.
        /// </summary>
        /// <param name="domain">An application domain</param>
        public ResolverHelper(AppDomain domain)
        {
            mydomain = domain;
            resolver = new ResolveEventHandler(this.Resolver);
        }
        /// <summary>
        ///  Empty constructor adds a ResolverHelper to the current AppDomains AssemblyResolveEvent.
        /// </summary>
        public ResolverHelper()
            : this(AppDomain.CurrentDomain)
        {
        }

        /// <summary>
        ///  Start using this ResolverHelper to resolve assemblies
        /// </summary>
        public void Activate()
        {
            mydomain.AssemblyResolve += resolver;
        }
        /// <summary>
        ///  Stop using this ResolverHelper to resolve assemblies
        /// </summary>
        public void Deactivate()
        {
            mydomain.AssemblyResolve -= resolver;
        }

        /// <summary>
        ///  This is the function that will actually try to find a missed assembly in the 
        /// additional paths.
        /// </summary>
        /// <param name="Sender">Normally an AppDomain</param>
        /// <param name="args">Event args from the failed search, basically the assembly name</param>
        /// <returns></returns>
        private System.Reflection.Assembly Resolver(Object Sender, System.ResolveEventArgs args)
        {
            String assemblyName = args.Name;
            String fullName = assemblyName + ".dll";
            foreach (string path in AdditionalPaths)
            {
                String fullPath = path + fullName;
                if (System.IO.File.Exists(fullPath))
                {
                    return System.Reflection.Assembly.LoadFile(fullPath);
                }
            }
            return null;
        }

    }


}

