HostFactory
using Autodesk.DesignScript.Geometry.Properties;
using Autodesk.DesignScript.Interfaces;
using Autodesk.DesignScript.Runtime;
using Dynamo.Events;
using Dynamo.Session;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
namespace Autodesk.DesignScript.Geometry
{
    [SupressImportIntoVM]
    public class HostFactory
    {
        private static readonly HostFactory mSelf;
        internal readonly IGeometryFactory mGeometryFactory;
        private readonly IPersistenceManager mPersistenceManager;
        private readonly List<IExtensionApplication> mExtensionApplications = new List<IExtensionApplication>();
        private readonly List<Type> mExtensionApplicationTypes = new List<Type>();
        private string mErrorString = string.Empty;
        private ConcurrentDictionary<int, ConcurrentBag<DesignScriptEntity>> itemsToDelete = new ConcurrentDictionary<int, ConcurrentBag<DesignScriptEntity>>();
        private double scaleFactor = 1;
        public static HostFactory Instance => mSelf;
        internal double ScaleFactor {
            get {
                return scaleFactor;
            }
            set {
                scaleFactor = value;
            }
        }
        internal static bool ExtensionApplicationStarted { get; set; }
        public static IGeometryFactory Factory {
            get {
                if (Instance.mGeometryFactory == null) {
                    if (string.IsNullOrEmpty(Instance.mErrorString))
                        Instance.mErrorString = Resources.NoImplementationException;
                    throw new NotImplementedException(Instance.mErrorString);
                }
                return Instance.mGeometryFactory;
            }
        }
        public static IPersistenceManager PersistenceManager => Instance.mPersistenceManager;
        internal static List<IExtensionApplication> ExtensionApplications => Instance.mExtensionApplications;
        static HostFactory()
        {
            mSelf = new HostFactory();
        }
        private unsafe HostFactory()
        {
            try {
                WorkspaceEvents.add_WorkspaceSettingsChanged(new WorkspaceSettingsChangedEventHandler((object)this, (IntPtr)(void*)));
                WorkspaceEvents.add_WorkspaceEnableLegacyPolyCurveSettingChanged(new WorkspaceSettingsChangedEventHandler((object)this, (IntPtr)(void*)));
                ExecutionEvents.add_GraphPostExecution(new ExecutionStateHandler((object)this, (IntPtr)(void*)));
                string factoryFilePath = null;
                bool flag = GetFactoryFileFromSessionConfig(ref factoryFilePath);
                if (!flag)
                    flag = GetFactoryFileFromGeometryConfig(ref factoryFilePath);
                if (flag && !string.IsNullOrEmpty(factoryFilePath))
                    factoryFilePath = GeometryExtension.LocateFile(factoryFilePath);
                if (mGeometryFactory == null && !string.IsNullOrEmpty(factoryFilePath))
                    mGeometryFactory = (CreateInstance(typeof(IGeometryFactory), factoryFilePath) as IGeometryFactory);
                if (!ExtensionApplicationStarted && mExtensionApplications.Count > 0) {
                    foreach (IExtensionApplication mExtensionApplication in mExtensionApplications) {
                        mExtensionApplication.OnBeginExecution(Application.Instance.Session);
                    }
                    ExtensionApplicationStarted = true;
                }
            } catch (Exception ex) {
                Exception innerException = ex.InnerException;
                mErrorString = ex.Message;
            }
        }
        public void StartUp(double scaleFactor = 1)
        {
            this.scaleFactor = scaleFactor;
            foreach (IExtensionApplication mExtensionApplication in mExtensionApplications) {
                mExtensionApplication.StartUp(default(ExtensionStartupParams));
            }
        }
        public void ShutDown()
        {
            foreach (IExtensionApplication mExtensionApplication in mExtensionApplications) {
                mExtensionApplication.ShutDown();
            }
        }
        public void PreloadAsmLibraries(string baseDirectory)
        {
            foreach (IExtensionApplication mExtensionApplication in mExtensionApplications) {
                mExtensionApplication.PreloadAsmLibraries(baseDirectory);
            }
        }
        internal void MarkDSEntityForDisposal(DesignScriptEntity entity)
        {
            ConcurrentBag<DesignScriptEntity> orAdd = itemsToDelete.GetOrAdd(entity.constructorThreadId, new ConcurrentBag<DesignScriptEntity>());
            orAdd.Add(entity);
        }
        internal void clearPendingDisposals()
        {
            int managedThreadId = Thread.CurrentThread.ManagedThreadId;
            if (itemsToDelete.TryGetValue(managedThreadId, out ConcurrentBag<DesignScriptEntity> value)) {
                while (!value.IsEmpty) {
                    if (value.TryTake(out DesignScriptEntity result))
                        result.Dispose();
                }
            }
        }
        private void ExecutionEvents_GraphPostExecution(IExecutionSession session)
        {
            clearPendingDisposals();
        }
        private void WorkspaceSettingsChanged(WorkspacesSettingsChangedEventArgs args)
        {
            ScaleFactor = args.get_ScaleFactor();
        }
        private void WorkspaceEnableLegacyPolyCurveSettingChanged(WorkspacesSettingsChangedEventArgs args)
        {
            IGeometryFactory obj = mGeometryFactory;
            if (obj != null)
                obj.SetEnableLegacyPolyCurveBehavior(args.get_EnableLegacyPolyCurveBehavior());
        }
        private static bool GetFactoryFileFromGeometryConfig(ref string factoryFilePath)
        {
            IProtoGeometryConfiguration settings = ProtoGeometryConfigurationManager.Settings;
            if (settings != null)
                factoryFilePath = settings.GeometryFactoryFileName;
            return !string.IsNullOrEmpty(factoryFilePath);
        }
        private static bool GetFactoryFileFromSessionConfig(ref string factoryFilePath)
        {
            IExecutionSession session = Application.Instance.Session;
            if (session == null)
                return false;
            IConfiguration val = session.get_Configuration();
            if (val == null)
                return false;
            factoryFilePath = (val.GetConfigValue(ConfigurationKeys.GeometryFactory) as string);
            return !string.IsNullOrEmpty(factoryFilePath);
        }
        private object CreateInstance(Type type, string library)
        {
            object obj = null;
            Type type2 = null;
            Type typeFromHandle = typeof(IExtensionApplication);
            Assembly assembly = Assembly.LoadFrom(library);
            Type[] exportedTypes = assembly.GetExportedTypes();
            Type[] array = exportedTypes;
            foreach (Type type3 in array) {
                if (!type3.IsAbstract) {
                    if (type.IsAssignableFrom(type3))
                        obj = Activator.CreateInstance(type3);
                    if (typeFromHandle.IsAssignableFrom(type3))
                        type2 = type3;
                    if ((Type)null != type2 && obj != null)
                        break;
                }
            }
            if (obj != null && (Type)null != type2 && !mExtensionApplicationTypes.Contains(type2)) {
                IExtensionApplication val = Activator.CreateInstance(type2) as IExtensionApplication;
                if (val != null) {
                    mExtensionApplicationTypes.Add(type2);
                    mExtensionApplications.Add(val);
                }
            }
            return obj;
        }
    }
}
            