DesignScriptEntity
using Autodesk.DesignScript.Geometry.Core;
using Autodesk.DesignScript.Geometry.Properties;
using Autodesk.DesignScript.Interfaces;
using Autodesk.DesignScript.Runtime;
using DynamoServices;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
namespace Autodesk.DesignScript.Geometry
{
    [SupressImportIntoVM]
    public abstract class DesignScriptEntity : IDisposable
    {
        protected internal IDesignScriptEntity mEntity;
        protected Func<IDesignScriptEntity> mConstructor;
        private const double AsmModelerUpperExtent = 10000;
        private const double AsmModelerLowerExtent = 0.0001;
        internal int constructorThreadId;
        internal bool disposedWrongThread;
        [SupressImportIntoVM]
        public EntityTags Tags = new EntityTags(null, null);
        private int? mHashCode;
        private static Dictionary<double, string> scaleRanges = new Dictionary<double, string> {
            {
                0.01,
                "Small"
            },
            {
                1,
                "Medium"
            },
            {
                100,
                "Large"
            },
            {
                10000,
                "Extra Large"
            }
        };
        internal bool IsDisposed { get; set; }
        public virtual Guid BaseTessellationGuid {
            get {
                IInstanceableGraphicItem val = mEntity as IInstanceableGraphicItem;
                if (val == null)
                    return new Guid("0CCF1293-E524-416D-8A2D-E57C0B4737E9");
                return val.get_BaseTessellationGuid();
            }
        }
        public virtual bool InstanceInfoAvailable {
            get {
                IInstanceableGraphicItem val = mEntity as IInstanceableGraphicItem;
                if (val != null)
                    return val.get_InstanceInfoAvailable();
                return false;
            }
        }
        internal virtual IDesignScriptEntity HostImpl {
            get {
                if (mEntity == null && mConstructor != null)
                    InitEntity(mConstructor());
                return mEntity;
            }
        }
        public static double scaleFactor => HostFactory.Instance.ScaleFactor;
        internal T Track<T>(T childGeometry) where T : DesignScriptEntity
        {
            childGeometry.Tags.Parent = this;
            return childGeometry;
        }
        internal IEnumerable<T> Track<T>(IEnumerable<T> childGeometries) where T : DesignScriptEntity
        {
            return from x in childGeometries
            select Track(x);
        }
        internal T[] Track<T>(T[] childGeometries) where T : DesignScriptEntity
        {
            return (from x in childGeometries
            select Track(x)).ToArray();
        }
        internal DesignScriptEntity(Func<IDesignScriptEntity> constructor)
        {
            mConstructor = constructor;
            constructorThreadId = Thread.CurrentThread.ManagedThreadId;
            HostFactory.Instance.clearPendingDisposals();
        }
        internal DesignScriptEntity(IDesignScriptEntity entity, bool persist = true)
        {
            InitEntity(entity);
        }
        internal void InitEntity(IDesignScriptEntity entity)
        {
            if (entity == null)
                throw new ArgumentNullException("host", Resources.NullIDesignScriptEntityException);
            if (entity.get_Owner() != null)
                throw new ArgumentException(Resources.OwnerExistingException, "host");
            mEntity = entity;
            mEntity.SetOwner((object)this);
            constructorThreadId = Thread.CurrentThread.ManagedThreadId;
            HostFactory.Instance.clearPendingDisposals();
        }
        public void Dispose()
        {
            if (Application.Instance.IsExecuting)
                DisposeDisplayable();
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void DisposeDisplayable()
        {
        }
        ~DesignScriptEntity()
        {
            Dispose(false);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!IsDisposed) {
                if (!disposing)
                    try {
                        HostFactory.Instance.MarkDSEntityForDisposal(this);
                    } catch (Exception) {
                    }
                else {
                    if (constructorThreadId != Thread.CurrentThread.ManagedThreadId)
                        disposedWrongThread = true;
                    ((IDisposable)mEntity).Dispose();
                    mEntity = null;
                    mConstructor = null;
                    IsDisposed = true;
                }
            }
        }
        public override string ToString()
        {
            return ((object)mEntity).ToString();
        }
        public sealed override int GetHashCode()
        {
            if (!mHashCode.HasValue)
                mHashCode = ComputeHashCode();
            return mHashCode.Value;
        }
        public sealed override bool Equals(object obj)
        {
            if (this == obj)
                return true;
            DesignScriptEntity designScriptEntity = obj as DesignScriptEntity;
            if (designScriptEntity == null)
                return false;
            return Equals(designScriptEntity);
        }
        public virtual void Tessellate(IRenderPackage package, TessellationParameters parameters)
        {
            IGraphicItem val = mEntity as IGraphicItem;
            if (val != null) {
                parameters.set_ScaleFactor(scaleFactor);
                val.Tessellate(package, parameters);
            }
        }
        void AddBaseTessellation(IInstancingRenderPackage package, TessellationParameters parameters)
        {
            IInstanceableGraphicItem val = mEntity as IInstanceableGraphicItem;
            if (val != null) {
                parameters.set_ScaleFactor(scaleFactor);
                val.AddBaseTessellation(package, parameters);
            }
        }
        void AddInstance(IInstancingRenderPackage package, TessellationParameters parameters, string labelKey)
        {
            IInstanceableGraphicItem val = mEntity as IInstanceableGraphicItem;
            if (val != null) {
                parameters.set_ScaleFactor(scaleFactor);
                val.AddInstance(package, parameters, labelKey);
            }
        }
        private static Tuple<string, double, double> RecommendedScaleFactor(double input)
        {
            double num = 0;
            double num2 = input / scaleFactor;
            if (num2 >= 10000) {
                double d = input / 10000;
                double num3 = Math.Log10(d);
                if (num3 % 1 == 0)
                    num3 += 1;
                num = Math.Ceiling(num3);
            } else if (num2 <= 0.0001) {
                double d2 = input / 0.0001;
                double num4 = Math.Log10(d2);
                if (num4 % 1 == 0)
                    num4 -= 1;
                num = Math.Floor(num4);
            }
            if (num % 2 != 0)
                num = ((num > 0) ? (num + 1) : (num - 1));
            if (num < -2)
                num = -2;
            if (num > 4)
                num = 4;
            double num5 = Math.Pow(10, num);
            return new Tuple<string, double, double>(scaleRanges[num5], num5 * 0.0001, num5 * 10000);
        }
        protected static void CheckArgsForAsmExtents(List<double> args)
        {
            double num = args.Max();
            double num2 = num / scaleFactor;
            if (num2 >= 10000) {
                Tuple<string, double, double> tuple = RecommendedScaleFactor(num);
                string empty = string.Empty;
                if (tuple.Item2 > 100000000)
                    empty = Resources.ModelerExtentsExceeded;
                else {
                    string outsideAllowableModelingRange = Resources.OutsideAllowableModelingRange;
                    string arg = tuple.Item1.ToString(CultureInfo.CurrentUICulture);
                    double num3 = tuple.Item2;
                    string arg2 = num3.ToString(CultureInfo.CurrentUICulture);
                    num3 = tuple.Item3;
                    empty = string.Format(outsideAllowableModelingRange, arg, arg2, num3.ToString("N0", CultureInfo.CurrentUICulture));
                }
                LogWarningMessageEvents.OnLogInfoMessage(empty);
            }
        }
        protected virtual bool Equals(DesignScriptEntity dsentity)
        {
            if (mEntity == null)
                return false;
            if (mEntity == dsentity.mEntity)
                return true;
            return ((object)mEntity).GetHashCode() == ((object)dsentity.mEntity).GetHashCode();
        }
        protected virtual int ComputeHashCode()
        {
            int num = (mEntity != null) ? ((object)mEntity).GetHashCode() : 0;
            if (num != 0)
                return num;
            return base.GetHashCode();
        }
    }
}
            