Geometry
using Autodesk.DesignScript.Geometry.Properties;
using Autodesk.DesignScript.Interfaces;
using Autodesk.DesignScript.Runtime;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Autodesk.DesignScript.Geometry
{
    public abstract class Geometry : DesignScriptEntity
    {
        private static Dictionary<Type, Func<IGeometryEntity, bool, Geometry>> mGeometryContructors;
        private Geometry mContext;
        private static Type mCachedType;
        private static Func<IGeometryEntity, bool, Geometry> mCachedConstructor;
        internal IPersistentObject mPersistent;
        public virtual BoundingBox BoundingBox => BoundingBox.Wrap(GeometryEntity.get_BoundingBox(), true);
        public virtual BoundingBox OrientedBoundingBox => BoundingBox.Wrap(GeometryEntity.get_OrientedBoundingBox(), true);
        public virtual CoordinateSystem ContextCoordinateSystem => CoordinateSystem.Wrap(GeometryEntity.get_ContextCoordinateSystem(), true);
        internal override IDesignScriptEntity HostImpl {
            get {
                if (mPersistent != null)
                    return mPersistent.get_Geometry();
                return base.HostImpl;
            }
        }
        internal IGeometryEntity GeometryEntity => HostImpl as IGeometryEntity;
        internal bool IsPersistent => mPersistent != null;
        static Geometry()
        {
            mGeometryContructors = new Dictionary<Type, Func<IGeometryEntity, bool, Geometry>>();
            Type[] types = Assembly.GetExecutingAssembly().GetTypes();
            Type[] array = types;
            foreach (Type type in array) {
                if (type.IsClass && !type.IsAbstract && typeof(Geometry).IsAssignableFrom(type)) {
                    MethodInfo method = type.GetMethod("InitType", BindingFlags.Static | BindingFlags.NonPublic);
                    if ((MethodInfo)null != method)
                        method.Invoke(null, null);
                }
            }
        }
        internal static void RegisterHostType(Type hostType, Func<IGeometryEntity, bool, Geometry> contructor)
        {
            mGeometryContructors[hostType] = contructor;
        }
        internal static Geometry Wrap(IGeometryEntity host, bool persist = false, Geometry context = null)
        {
            if (host == null)
                return null;
            if (host.get_Owner() != null)
                return host.get_Owner() as Geometry;
            Func<IGeometryEntity, bool, Geometry> geomConstructor = GetGeomConstructor(host);
            if (geomConstructor == null)
                throw new InvalidOperationException(string.Format(Resources.InvalidOperationException, ((object)host).GetType()));
            return geomConstructor(host, persist);
        }
        internal static Geometry[] Wrap(IGeometryEntity[] geometries)
        {
            List<Geometry> list = new List<Geometry>();
            foreach (IGeometryEntity host in geometries) {
                list.Add(Wrap(host, false, null));
            }
            return list.ToArray();
        }
        internal static IGeometryEntity[] Unwrap(Geometry[] geometries)
        {
            List<IGeometryEntity> list = new List<IGeometryEntity>();
            foreach (Geometry geometry in geometries) {
                list.Add(geometry.GeometryEntity);
            }
            return list.ToArray();
        }
        internal static IGeometryEntity[] Unwrap(IEnumerable<Geometry> o)
        {
            return (from x in o
            select Unwrap(x)).ToArray();
        }
        internal static IGeometryEntity Unwrap(Geometry geom)
        {
            return geom.GeometryEntity;
        }
        private static Func<IGeometryEntity, bool, Geometry> GetGeomConstructor(IGeometryEntity host)
        {
            Type type = ((object)host).GetType();
            if (type == mCachedType)
                return mCachedConstructor;
            Type[] interfaces = type.GetInterfaces();
            interfaces = interfaces.Except(interfaces.SelectMany((Type t) => t.GetInterfaces())).ToArray();
            Type[] array = interfaces;
            foreach (Type key in array) {
                if (mGeometryContructors.TryGetValue(key, out Func<IGeometryEntity, bool, Geometry> value)) {
                    mCachedType = type;
                    mCachedConstructor = value;
                    return value;
                }
            }
            return null;
        }
        internal Geometry(IGeometryEntity host, bool persist)
            : base(host, true)
        {
            InitGeometry(persist);
        }
        internal Geometry(Func<IGeometryEntity> constructor, bool persist)
            : base((Func<IDesignScriptEntity>)constructor)
        {
            InitGeometry(persist);
        }
        [IsVisibleInDynamoLibrary(false)]
        public static Geometry FromObject(long ptr)
        {
            IPersistentObject val = HostFactory.PersistenceManager.FromObject(ptr);
            Geometry geometry = Wrap(val.get_Geometry(), false, null);
            geometry.mPersistent = val;
            return geometry;
        }
        private void InitGeometry(bool persist)
        {
            if (persist)
                Persist();
        }
        internal IPersistentObject Persist()
        {
            if (mPersistent != null)
                return mPersistent;
            if ((object)HostFactory.PersistenceManager == null)
                return null;
            IGeometryEntity val = HostImpl as IGeometryEntity;
            if (val == null)
                return null;
            DisposeDisplay();
            mPersistent = HostFactory.PersistenceManager.Persist(val);
            return mPersistent;
        }
        protected override void DisposeDisplayable()
        {
            DisposeDisplay();
            if (mPersistent != null)
                mPersistent.Erase();
            base.DisposeDisplayable();
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing) {
                if (mPersistent != null && (object)mPersistent != (object)base.HostImpl)
                    ((IDisposable)mPersistent).Dispose();
                GeometryExtension.DisposeObject(ref mContext);
            }
            mPersistent = null;
            base.Dispose(disposing);
        }
        private void DisposeDisplay()
        {
        }
        internal static int GetIndexOfNearestGeometry(IGeometryEntity[] entities, IPointEntity point)
        {
            double num = entities[0].DistanceTo(point);
            int result = 0;
            for (int i = 1; i < entities.Length; i++) {
                double num2 = entities[i].DistanceTo(point);
                if (num2 < num) {
                    num = num2;
                    result = i;
                }
            }
            return result;
        }
        public virtual Geometry Translate(double xTranslation = 0, double yTranslation = 0, double zTranslation = 0)
        {
            DesignScriptEntity.CheckArgsForAsmExtents(new List<double> {
                xTranslation,
                yTranslation,
                zTranslation
            });
            xTranslation /= DesignScriptEntity.scaleFactor;
            yTranslation /= DesignScriptEntity.scaleFactor;
            zTranslation /= DesignScriptEntity.scaleFactor;
            IGeometryEntity host = GeometryEntity.Translate(xTranslation, yTranslation, zTranslation) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Translate(Vector direction)
        {
            IGeometryEntity host = GeometryEntity.Translate(direction.VectorEntity) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Translate(Vector direction, double distance)
        {
            DesignScriptEntity.CheckArgsForAsmExtents(new List<double> {
                distance
            });
            distance /= DesignScriptEntity.scaleFactor;
            IGeometryEntity host = GeometryEntity.Translate(direction.VectorEntity, distance) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Transform(CoordinateSystem cs)
        {
            IGeometryEntity host = GeometryEntity.Transform(cs.CoordinateSystemEntity) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Transform(CoordinateSystem fromCoordinateSystem, CoordinateSystem contextCoordinateSystem)
        {
            IGeometryEntity host = GeometryEntity.TransformFromTo(fromCoordinateSystem.CoordinateSystemEntity, contextCoordinateSystem.CoordinateSystemEntity) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Rotate(Point origin, Vector axis, double degrees = 0)
        {
            IGeometryEntity host = GeometryEntity.Rotate(origin.PointEntity, axis.VectorEntity, degrees) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Rotate(Plane basePlane, double degrees = 0)
        {
            IGeometryEntity host = GeometryEntity.Rotate(basePlane.PlaneEntity, degrees) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Mirror(Plane mirrorPlane)
        {
            IGeometryEntity host = GeometryEntity.Mirror(mirrorPlane.PlaneEntity) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Scale(double amount = 1)
        {
            IGeometryEntity host = GeometryEntity.Scale(amount) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Scale(double xamount = 1, double yamount = 1, double zamount = 1)
        {
            IGeometryEntity host = GeometryEntity.Scale(xamount, yamount, zamount) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Scale(Plane plane, double xamount = 1, double yamount = 1, double zamount = 1)
        {
            IGeometryEntity host = GeometryEntity.Scale(Plane.Unwrap(plane), xamount, yamount, zamount) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Scale(Point basePoint, Point from, Point to)
        {
            IGeometryEntity host = GeometryEntity.Scale(basePoint.PointEntity, from.PointEntity, to.PointEntity) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Scale1D(Point basePoint, Point from, Point to)
        {
            IGeometryEntity host = GeometryEntity.Scale1D(basePoint.PointEntity, from.PointEntity, to.PointEntity) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual Geometry Scale2D(Plane basePlane, Point from, Point to)
        {
            IGeometryEntity host = GeometryEntity.Scale2D(basePlane.PlaneEntity, from.PointEntity, to.PointEntity) as IGeometryEntity;
            return Wrap(host, true, null);
        }
        public virtual double DistanceTo(Geometry other)
        {
            return GeometryEntity.DistanceTo(other.GeometryEntity) * DesignScriptEntity.scaleFactor;
        }
        public virtual Point ClosestPointTo(Geometry other)
        {
            IPointEntity host = GeometryEntity.ClosestPointTo(other.GeometryEntity);
            return Point.Wrap(host, true);
        }
        public bool DoesIntersect(Geometry other)
        {
            return GeometryEntity.DoesIntersect(other.GeometryEntity);
        }
        public Geometry[] Intersect(Geometry other)
        {
            return Wrap(GeometryEntity.Intersect(other.GeometryEntity));
        }
        public Geometry[] IntersectAll(IEnumerable<Geometry> others)
        {
            return Wrap(GeometryEntity.IntersectAll(Unwrap(others)));
        }
        public virtual Geometry[] Split(Geometry other)
        {
            return Wrap(GeometryEntity.Split(other.GeometryEntity));
        }
        public virtual Geometry[] Trim(Geometry other, Point pick)
        {
            return Wrap(GeometryEntity.Trim(other.GeometryEntity, pick.PointEntity));
        }
        public virtual Geometry[] Explode()
        {
            return Track(Wrap(GeometryEntity.Explode())).ToArray();
        }
        public virtual bool IsAlmostEqualTo(Geometry other)
        {
            return GeometryEntity.IsAlmostEqualTo(other.GeometryEntity);
        }
        public string ToSolidDef()
        {
            return GeometryEntity.ToSolidDef();
        }
        [SupressImportIntoVM]
        public virtual string ToJson()
        {
            return GeometryEntity.ToJson(DesignScriptEntity.scaleFactor);
        }
        [IsVisibleInDynamoLibrary(false)]
        public virtual Geometry[] Approximate()
        {
            return Wrap(GeometryEntity.Approximate());
        }
        internal Geometry SetAttributes(Dictionary<string, string> attributes)
        {
            return Wrap(GeometryEntity.SetAttributes(attributes), false, null);
        }
        internal IDictionary<string, string> GetAttributes()
        {
            return GeometryEntity.GetAttributes();
        }
        [AllowRankReduction]
        [Obsolete("This method is deprecated and will be removed in a future version of Dynamo. Use overload that specifies mm per unit")]
        [IsObsolete("geometry_importfromsat_deprecated", typeof(Resources))]
        public static Geometry[] ImportFromSAT(FileInfo file)
        {
            string fileName = file.FullName;
            IGeometryEntity[] hosts = ImportFromSAT(ref fileName, 1000);
            return hosts.ToArray<Geometry, IGeometryEntity>(true, (Geometry)null);
        }
        [AllowRankReduction]
        [Obsolete("This method is deprecated and will be removed in a future version of Dynamo. Use overload that specifies mm per unit")]
        [IsObsolete("geometry_importfromsat_deprecated", typeof(Resources))]
        public static Geometry[] ImportFromSAT(string filePath)
        {
            IGeometryEntity[] hosts = ImportFromSAT(ref filePath, 1000);
            return hosts.ToArray<Geometry, IGeometryEntity>(true, (Geometry)null);
        }
        [AllowRankReduction]
        [IsVisibleInDynamoLibrary(false)]
        public static Geometry[] ImportFromSAT(FileInfo file, double mmPerUnit)
        {
            string fileName = file.FullName;
            IGeometryEntity[] hosts = ImportFromSAT(ref fileName, mmPerUnit);
            return hosts.ToArray<Geometry, IGeometryEntity>(true, (Geometry)null);
        }
        [AllowRankReduction]
        [IsVisibleInDynamoLibrary(false)]
        public static Geometry[] ImportFromSAT(string filePath, double mmPerUnit)
        {
            IGeometryEntity[] hosts = ImportFromSAT(ref filePath, mmPerUnit);
            return hosts.ToArray<Geometry, IGeometryEntity>(true, (Geometry)null);
        }
        internal static IGeometryEntity[] ImportFromSAT(ref string fileName, double mmPerUnit)
        {
            if (string.IsNullOrWhiteSpace(fileName))
                throw new ArgumentNullException("fileName");
            fileName = GeometryExtension.LocateFile(fileName);
            if (!File.Exists(fileName))
                throw new ArgumentException(string.Format(Resources.FileNotFound, fileName), "fileName");
            return HostFactory.Factory.LoadSAT(fileName, DesignScriptEntity.scaleFactor, mmPerUnit);
        }
        [AllowRankReduction]
        public static Geometry[] FromSolidDef(string solidDefJson)
        {
            IGeometryEntity[] hosts = FromSolidDef(ref solidDefJson);
            return hosts.ToArray<Geometry, IGeometryEntity>(true, (Geometry)null);
        }
        internal static IGeometryEntity[] FromSolidDef(ref string solidDefJson)
        {
            if (string.IsNullOrWhiteSpace(solidDefJson))
                throw new ArgumentNullException("solidDefJson");
            return HostFactory.Factory.FromSolidDef(solidDefJson);
        }
        [SupressImportIntoVM]
        public static Geometry FromJson(string json)
        {
            return Wrap(HostFactory.Factory.GeometryFromJson(json, DesignScriptEntity.scaleFactor), false, null);
        }
        [SupressImportIntoVM]
        [Obsolete("This method is deprecated and will be removed in a future version of Dynamo. Use ExportToSAT(IEnumerable<Geometry> geometry, string filePath) instead")]
        public string ExportToSAT(string filePath)
        {
            List<Geometry> list = new List<Geometry>();
            list.Add(this);
            return ExportToSAT(list.ToArray(), filePath);
        }
        [SupressImportIntoVM]
        [Obsolete("This method is deprecated and will be removed in a future version of Dynamo. Use ExportToSAT UI node instead")]
        public string ExportToSAT(string filePath, double unitsMM)
        {
            List<Geometry> list = new List<Geometry>();
            list.Add(this);
            return ExportToSAT(list.ToArray(), filePath, unitsMM);
        }
        public static string ExportToSAT(IEnumerable<Geometry> geometry, string filePath)
        {
            return CheckPathAndExportToSAT(geometry, filePath, false, 0);
        }
        [Obsolete("This method is deprecated and will be removed in a future version of Dynamo. Use ExportToSAT UI node instead")]
        [IsObsolete("geometry_exporttosat_deprecated", typeof(Resources))]
        public static string ExportToSAT(IEnumerable<Geometry> geometry, string filePath, double unitsMM)
        {
            return CheckPathAndExportToSAT(geometry, filePath, true, unitsMM);
        }
        [IsVisibleInDynamoLibrary(false)]
        public static Geometry[] FromNativePointer(IntPtr nativePointer)
        {
            IGeometryEntity[] hosts = HostFactory.Factory.FromNativePointer(nativePointer, DesignScriptEntity.scaleFactor);
            return hosts.ToArray<Geometry, IGeometryEntity>(true, (Geometry)null);
        }
        [IsVisibleInDynamoLibrary(false)]
        public static IntPtr[] ToNativePointer(IEnumerable<Geometry> geometry)
        {
            List<IGeometryEntity> list = new List<IGeometryEntity>();
            foreach (Geometry item in geometry) {
                IGeometryEntity geometryEntity = item.GeometryEntity;
                if (geometryEntity != null)
                    list.Add(geometryEntity);
            }
            object factory = (object)HostFactory.Factory;
            object[] array = list.ToArray();
            return factory.ToNativePointer(array, DesignScriptEntity.scaleFactor);
        }
        private static string CheckPathAndExportToSAT(IEnumerable<Geometry> geometry, string filePath, bool useUnits, double unitsMM = 0)
        {
            List<IGeometryEntity> list = new List<IGeometryEntity>();
            foreach (Geometry item in geometry) {
                IGeometryEntity geometryEntity = item.GeometryEntity;
                if (geometryEntity != null)
                    list.Add(geometryEntity);
            }
            if (list.Count == 0)
                throw new Exception(Resources.ConversionException);
            if (!filePath.EndsWith(".sat"))
                filePath += ".sat";
            if (!Path.IsPathRooted(filePath)) {
                string text = GeometrySettings.RootModulePath;
                if (string.IsNullOrEmpty(text))
                    text = AppDomain.CurrentDomain.BaseDirectory;
                string directoryName = Path.GetDirectoryName(text);
                filePath = Path.Combine(directoryName, filePath);
            }
            object[] array;
            if (!useUnits) {
                object factory = (object)HostFactory.Factory;
                string text2 = filePath;
                array = list.ToArray();
                return factory.SaveSAT(text2, array, DesignScriptEntity.scaleFactor);
            }
            object factory2 = (object)HostFactory.Factory;
            string text3 = filePath;
            array = list.ToArray();
            return factory2.SaveSAT(text3, array, unitsMM, DesignScriptEntity.scaleFactor);
        }
        [SupressImportIntoVM]
        [Obsolete("This method is deprecated and will be removed in a future version of Dynamo. Use SerializeAsSAB(IEnumerable<Geometry> geometry")]
        public byte[] SerializeAsSAB()
        {
            List<Geometry> list = new List<Geometry>();
            list.Add(this);
            return SerializeAsSAB(list.ToArray());
        }
        public static byte[] SerializeAsSAB(IEnumerable<Geometry> geometry)
        {
            List<IGeometryEntity> list = new List<IGeometryEntity>();
            foreach (Geometry item in geometry) {
                IGeometryEntity geometryEntity = item.GeometryEntity;
                if (geometryEntity != null)
                    list.Add(geometryEntity);
            }
            object factory = (object)HostFactory.Factory;
            object[] array = list.ToArray();
            return factory.SerializeAsSAB(array, DesignScriptEntity.scaleFactor);
        }
        [AllowRankReduction]
        [Obsolete("This method is deprecated and will be removed in a future version of Dynamo. Please use overload that allows passing mmPerUnit")]
        [IsObsolete("geometry_deserializefromsab_deprecated", typeof(Resources))]
        public static Geometry[] DeserializeFromSAB(byte[] buffer)
        {
            IGeometryEntity[] hosts = DeserializeFromSABInternal(buffer, 1000);
            return hosts.ToArray<Geometry, IGeometryEntity>(true, (Geometry)null);
        }
        [AllowRankReduction]
        [IsVisibleInDynamoLibrary(false)]
        public static Geometry[] DeserializeFromSAB(byte[] buffer, double mmPerUnit)
        {
            IGeometryEntity[] hosts = DeserializeFromSABInternal(buffer, mmPerUnit);
            return hosts.ToArray<Geometry, IGeometryEntity>(true, (Geometry)null);
        }
        internal static IGeometryEntity[] DeserializeFromSABInternal(byte[] buffer, double mmPerUnit)
        {
            return HostFactory.Factory.DeserializeFromSAB(buffer, DesignScriptEntity.scaleFactor, mmPerUnit);
        }
        [SupressImportIntoVM]
        public static void UpdateDisplay()
        {
            HostFactory.PersistenceManager.UpdateDisplay();
        }
        protected override int ComputeHashCode()
        {
            int num = (mPersistent != null) ? ((object)mPersistent).GetHashCode() : 0;
            if (num != 0)
                return num;
            return base.ComputeHashCode();
        }
        internal static string GetFullPath(string fileName)
        {
            if (Path.IsPathRooted(fileName))
                return fileName;
            IConfiguration val = Application.Instance.Session as IConfiguration;
            return Path.Combine(Path.GetDirectoryName(val.get_RootModulePath()), fileName);
        }
    }
}
            