/// <summary>
 /// The public Create function.
 /// </summary>
 /// <param name="hnd">The opening handle.</param>
 /// <param name="placement">The opening local placement.</param>
 /// <param name="height">The opening height.</param>
 /// <param name="width">The opening width.</param>
 /// <returns>The DoorWindowOpeningInfo class.</returns>
 static public DoorWindowOpeningInfo Create(IFCAnyHandle hnd, double height, double width)
 {
     DoorWindowOpeningInfo doorWindowOpeningInfo = new DoorWindowOpeningInfo();
     doorWindowOpeningInfo.m_OpeningHnd = hnd;
     doorWindowOpeningInfo.m_OpeningHeight = height;
     doorWindowOpeningInfo.m_OpeningWidth = width;
     return doorWindowOpeningInfo;
 }
        /// <summary>
        /// The public Create function.
        /// </summary>
        /// <param name="hnd">The opening handle.</param>
        /// <param name="placement">The opening local placement.</param>
        /// <param name="height">The opening height.</param>
        /// <param name="width">The opening width.</param>
        /// <returns>The DoorWindowOpeningInfo class.</returns>
        static public DoorWindowOpeningInfo Create(IFCAnyHandle hnd, double height, double width)
        {
            DoorWindowOpeningInfo doorWindowOpeningInfo = new DoorWindowOpeningInfo();

            doorWindowOpeningInfo.m_OpeningHnd    = hnd;
            doorWindowOpeningInfo.m_OpeningHeight = height;
            doorWindowOpeningInfo.m_OpeningWidth  = width;
            return(doorWindowOpeningInfo);
        }
        /// <summary>
        /// Excutes the creator.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="doc">The document.</param>
        public void Execute(ExporterIFC exporterIFC, Document doc)
        {
            IFCAnyHandle hostObjHnd = !IFCAnyHandleUtil.IsNullOrHasNoValue(HostHnd) ? HostHnd :
                                      DoorWindowUtil.GetHndForHostAndLevel(exporterIFC, HostId, LevelId);

            if (IFCAnyHandleUtil.IsNullOrHasNoValue(hostObjHnd))
            {
                return;
            }

            IList <DoorWindowOpeningInfo> doorWindowOpeningInfoList = new List <DoorWindowOpeningInfo>();

            Element doorElem    = doc.GetElement(InsertId);
            string  openingGUID = GUIDUtil.CreateSubElementGUID(doorElem, (int)IFCDoorSubElements.DoorOpening);

            if (ExtrusionData != null)
            {
                foreach (IFCExtrusionData extrusionData in ExtrusionData)
                {
                    if (doorWindowOpeningInfoList.Count > 0)
                    {
                        openingGUID = GUIDUtil.CreateGUID();
                    }
                    DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd,
                                                                                                  HostId, InsertId, openingGUID, extrusionData.GetLoops()[0], extrusionData.ExtrusionDirection,
                                                                                                  UnitUtil.UnscaleLength(extrusionData.ScaledExtrusionLength), PosHingeSide, IsRecess);
                    if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd))
                    {
                        doorWindowOpeningInfoList.Add(openingInfo);
                    }
                }
            }

            if (Solids != null)
            {
                foreach (Solid solid in Solids)
                {
                    if (doorWindowOpeningInfoList.Count > 0)
                    {
                        openingGUID = GUIDUtil.CreateGUID();
                    }
                    DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd,
                                                                                                  HostId, InsertId, openingGUID, solid, ScaledHostWidth, IsRecess);
                    if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd))
                    {
                        doorWindowOpeningInfoList.Add(openingInfo);
                    }
                }
            }

            if (IFCAnyHandleUtil.IsNullOrHasNoValue(DoorWindowHnd))
            {
                return;
            }

            bool foundOpening          = false;
            bool foundHeight           = false;
            bool foundWidth            = false;
            bool?isDoorOrWindowOpening = null;

            foreach (DoorWindowOpeningInfo openingInfo in doorWindowOpeningInfoList)
            {
                // If we've updated the door/window placement, and set its height and width, there's nothing more to do here.
                if (foundOpening && foundHeight && foundWidth)
                {
                    break;
                }

                // update original door or window to be relative to the first opening we find.
                // We only allow one IfcRelFillsElement per door or window, so only do this for the first opening.
                if (!foundOpening)
                {
                    IFCFile      file         = exporterIFC.GetFile();
                    IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle;

                    IFCAnyHandle openingHnd = openingInfo.OpeningHnd;

                    foundOpening = true;
                    string relGUID = GUIDUtil.CreateGUID();
                    IFCInstanceExporter.CreateRelFillsElement(file, relGUID, ownerHistory, null, null, openingHnd, DoorWindowHnd);

                    IFCAnyHandle openingPlacement = IFCAnyHandleUtil.GetObjectPlacement(openingHnd);
                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(openingPlacement))
                    {
                        IFCAnyHandle origObjectPlacement = IFCAnyHandleUtil.GetObjectPlacement(DoorWindowHnd);
                        Transform    relTransform        = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(origObjectPlacement, openingPlacement);

                        IFCAnyHandle newLocalPlacement = ExporterUtil.CreateLocalPlacement(file, openingPlacement,
                                                                                           relTransform.Origin, relTransform.BasisZ, relTransform.BasisX);

                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "ObjectPlacement", newLocalPlacement);
                        origObjectPlacement.Delete();
                    }
                }

                // The first entry for a particular door may not have the height or width set, so keep looking until we find an entry that does.
                if (!isDoorOrWindowOpening.HasValue)
                {
                    isDoorOrWindowOpening = IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcDoor) || IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcWindow);
                }

                if (!(foundHeight && foundWidth) && isDoorOrWindowOpening.Value)
                {
                    double openingHeight = openingInfo.OpeningHeight;
                    double openingWidth  = openingInfo.OpeningWidth;

                    if (openingHeight > MathUtil.Eps())
                    {
                        foundHeight = true;
                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallHeight", UnitUtil.ScaleLength(openingHeight));
                    }

                    if (openingWidth > MathUtil.Eps())
                    {
                        foundWidth = true;
                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallWidth", UnitUtil.ScaleLength(openingWidth));
                    }
                }
            }
        }
        /// <summary>
        /// Excutes the creator.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="doc">The document.</param>
        public void Execute(ExporterIFC exporterIFC, Document doc)
        {
            IFCAnyHandle hostObjHnd = !IFCAnyHandleUtil.IsNullOrHasNoValue(HostHnd) ? HostHnd :
                                      DoorWindowUtil.GetHndForHostAndLevel(exporterIFC, HostId, LevelId);

            if (IFCAnyHandleUtil.IsNullOrHasNoValue(hostObjHnd))
            {
                return;
            }

            IList <DoorWindowOpeningInfo> doorWindowOpeningInfoList = new List <DoorWindowOpeningInfo>();

            Element doorElem    = doc.GetElement(InsertId);
            string  openingGUID = GUIDUtil.CreateSubElementGUID(doorElem, (int)IFCDoorSubElements.DoorOpening);

            if (ExtrusionData != null)
            {
                foreach (IFCExtrusionData extrusionData in ExtrusionData)
                {
                    if (doorWindowOpeningInfoList.Count > 0)
                    {
                        openingGUID = GUIDUtil.CreateGUID();
                    }
                    DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd,
                                                                                                  HostId, InsertId, openingGUID, extrusionData.GetLoops()[0], extrusionData.ExtrusionDirection,
                                                                                                  UnitUtil.UnscaleLength(extrusionData.ScaledExtrusionLength), PosHingeSide, IsRecess);
                    if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd))
                    {
                        doorWindowOpeningInfoList.Add(openingInfo);
                    }
                }
            }

            if (Solids != null)
            {
                foreach (Solid solid in Solids)
                {
                    if (doorWindowOpeningInfoList.Count > 0)
                    {
                        openingGUID = GUIDUtil.CreateGUID();
                    }
                    DoorWindowOpeningInfo openingInfo = DoorWindowUtil.CreateOpeningForDoorWindow(exporterIFC, doc, hostObjHnd,
                                                                                                  HostId, InsertId, openingGUID, solid, ScaledHostWidth, IsRecess);
                    if (openingInfo != null && !IFCAnyHandleUtil.IsNullOrHasNoValue(openingInfo.OpeningHnd))
                    {
                        doorWindowOpeningInfoList.Add(openingInfo);
                    }
                }
            }

            if (IFCAnyHandleUtil.IsNullOrHasNoValue(DoorWindowHnd))
            {
                return;
            }

            foreach (DoorWindowOpeningInfo openingInfo in doorWindowOpeningInfoList)
            {
                IFCFile      file         = exporterIFC.GetFile();
                IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

                IFCAnyHandle openingHnd    = openingInfo.OpeningHnd;
                double       openingHeight = openingInfo.OpeningHeight;
                double       openingWidth  = openingInfo.OpeningWidth;

                // update original door.
                string relGUID = GUIDUtil.CreateGUID();
                IFCInstanceExporter.CreateRelFillsElement(file, relGUID, ownerHistory, null, null, openingHnd, DoorWindowHnd);

                IFCAnyHandle openingPlacement = IFCAnyHandleUtil.GetObjectPlacement(openingHnd);
                if (!IFCAnyHandleUtil.IsNullOrHasNoValue(openingPlacement))
                {
                    IFCAnyHandle origObjectPlacement = IFCAnyHandleUtil.GetObjectPlacement(DoorWindowHnd);
                    Transform    relTransform        = ExporterIFCUtils.GetRelativeLocalPlacementOffsetTransform(origObjectPlacement, openingPlacement);

                    IFCAnyHandle newLocalPlacement = ExporterUtil.CreateLocalPlacement(file, openingPlacement,
                                                                                       relTransform.Origin, relTransform.BasisZ, relTransform.BasisX);

                    IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "ObjectPlacement", newLocalPlacement);
                    origObjectPlacement.Delete();
                }

                if (IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcDoor) ||
                    IFCAnyHandleUtil.IsTypeOf(DoorWindowHnd, IFCEntityType.IfcWindow))
                {
                    if (openingHeight > MathUtil.Eps())
                    {
                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallHeight", UnitUtil.ScaleLength(openingHeight));
                    }
                    if (openingWidth > MathUtil.Eps())
                    {
                        IFCAnyHandleUtil.SetAttribute(DoorWindowHnd, "OverallWidth", UnitUtil.ScaleLength(openingWidth));
                    }
                }
            }
        }