/*-------------------------------------------------------------------------
 * 功能描述:RevitUtil
 * 作者:xulisong
 * 创建时间: 2019/6/24 9:55:09
 * 版本号:v1.0
 *  -------------------------------------------------------------------------*/

using Autodesk.Revit.DB;
using SAGA.RevitUtils.Extends;
using SAGA.RevitUtils.Extends.Graphic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB.Mechanical;
using RevitToJBim.Extension;
using RevitToJBim.MBI;
using SAGA.DotNetUtils;
using Parameter=JBIM.Component.Parameter;
using SAGA.RevitUtils;
using SAGA.DotNetUtils.Extend;

namespace RevitToJBim.Common
{
    public class RevitUtil
    {
        /// <summary>
        /// 获取FamilyInstance顶面轮廓
        /// </summary>
        /// <param name="fi"></param>
        /// <returns></returns>
        public static List<XYZ> GetTopPolygon(FamilyInstance fi)
        {
            List<XYZ> path = new List<XYZ>();
            var faces = fi.GetOriginalFaces(XYZ.BasisZ);
            var topface = faces.FirstOrDefault();
            //传递的path中没有重复点
            if (topface != null)
            {
                var curves = topface.GetCurves();
                for (int i = 0; i < curves.Count; i++)
                {
                    var current = curves[i];
                    var points = current.GetPoints();
                    points.RemoveAt(points.Count - 1);
                    path.AddRange(points);
                }
            }

            return path;
        }
        /// <summary>
        /// 获取FamilyInstance box底面轮廓
        /// </summary>
        /// <param name="fi"></param>
        /// <returns></returns>
        public static List<XYZ> GetBottomPolygon(FamilyInstance fi)
        {
            List<XYZ> path=new List<XYZ>();
            try
            {
                var box = fi.get_BoundingBox(null);
                if (box == null) return path;
                var boxMin = box.Min;
                var boxMax = box.Max;
                path.Add(boxMin);
                path.Add(boxMin.NewX(boxMax.X));
                path.Add(boxMin.NewX(boxMax.X).NewY(boxMax.Y));
                path.Add(boxMin.NewY(boxMax.Y));
                path.Add(boxMin);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            
            return path;
        }
        /// <summary>
        /// 获取设备设施的参数
        /// </summary>
        /// <param name="fi"></param>
        /// <returns></returns>
        public static List<Parameter> GetFacilityParameters(FamilyInstance fi)
        {
            List<string> parameterNames=new List<string>(){ MBIBuiltInParameterName.EquipLocalName,MBIBuiltInParameterName.EquipLocalID,MBIBuiltInParameterName.PropertyID };
            List<Parameter> parameters=new List<Parameter>();
            foreach (var parameterName in parameterNames)
            {
                var revitParameter = fi.GetParameter(parameterName);
                if (revitParameter != null)
                {
                    var parameter = new Parameter(ParameterUtil.FindParameterDefine(parameterName));
                    parameter.Value = revitParameter.AsString();
                    parameters.Add(parameter);
                }
            }

            return parameters;
        }

        /// <summary>
        /// 获取设备设施的参数
        /// </summary>
        /// <param name="space"></param>
        /// <returns></returns>
        public static List<Parameter> GetSpaceParameters(Space space)
        {
            List<string> parameterNames = new List<string>() { MBIBuiltInParameterName.SpaceName, MBIBuiltInParameterName.SpaceNumber };
            List<Parameter> parameters = new List<Parameter>();
            foreach (var parameterName in parameterNames)
            {
                var revitParameter = space.GetParameter(parameterName);
                if (revitParameter != null)
                {
                    var parameter = new Parameter(ParameterUtil.FindParameterDefine(parameterName));
                    parameter.Value = revitParameter.AsString();
                    parameters.Add(parameter);
                }
            }

            return parameters;
        }
        /// <summary>
        /// 获取设备设施的参数
        /// </summary>
        /// <param name="space"></param>
        /// <returns></returns>
        public static List<Parameter> GetMEPCurveParameters(MEPCurve curve)
        {
            List<string> parameterNames = new List<string>() { MBIBuiltInParameterName.MEPCurveComments};
            List<Parameter> parameters = new List<Parameter>();
            foreach (var parameterName in parameterNames)
            {
                var revitParameter = curve.GetParameter(parameterName);
                if (revitParameter != null)
                {
                    var parameter = new Parameter(ParameterUtil.FindParameterDefine(parameterName));
                    parameter.Value = revitParameter.AsString();
                    parameters.Add(parameter);
                }
            }

            return parameters;
        }

        /// <summary>
        /// 获取部件所关联的设备
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static Element GetEquipPartParent(Element element)
        {
            if (!element.IsEquipmentPart()) return null;
            string code = element.GetFamilyName()?.Substring(0, 4); ;
            if (code.IsNullOrEmpty()) return null;
            //构件所关联的设备
            var parentInst = element.Document.GetElements(new ElementIntersectsElementFilter(element))
                .FirstOrDefault(t => !t.Id.IsEqual(element.Id) && t.GetFamilyCode() == code);
            return parentInst;
        }

        /// <summary>
        /// 获取门窗到墙线上的投影线
        /// </summary>
        /// <param name="fi"></param>
        /// <returns></returns>
        public static List<XYZ> GetWindowDoorLocation(FamilyInstance fi)
        {
            //取几何实体顶点信息,将点到指定方向做投影
            List<XYZ> xyzs = GetVertexPoints(fi);
            XYZ handDirection = (fi.Host as Wall)?.Orientation;
            if (handDirection != null)
            {
                handDirection = handDirection.CrossProduct(XYZ.BasisZ);
            }
            else if (handDirection == null)
            {
                handDirection = fi.HandOrientation;
            }
            var location = fi.GetLocationPoint();
            if (location == null)
            {
                location = xyzs.FirstOrDefault();
            }

            double min = 0, max = 0;
            XYZ minXYZ = XYZ.Zero, maxXYZ = XYZ.Zero;
            for (int i = 0; i < xyzs.Count; i++)
            {
                var usePoint = xyzs[i];
                var refDirection = usePoint - location;
                var offset = refDirection.DotProduct(handDirection);
                var projectPoint = location.OffsetPoint(handDirection, offset);
                #region 初始化逻辑
                if (i == 0)
                {
                    minXYZ = maxXYZ = projectPoint;
                    min = max = offset;
                }
                #endregion
                #region 判定逻辑
                else
                {
                    if (offset < min)
                    {
                        minXYZ = projectPoint;
                        min = offset;
                        continue;
                    }
                    if (max < offset)
                    {
                        maxXYZ = projectPoint;
                        max = offset;
                        continue;
                    }
                }
                #endregion
            }
            return new List<XYZ>() { minXYZ, maxXYZ };
        }

        /// <summary>
        /// 获取元素顶点集合
        /// </summary>
        /// <returns></returns>
        public static List<XYZ> GetVertexPoints(Element element)
        {
            List<XYZ> xyzs = new List<XYZ>();
            //string id = element.Id.ToString();
            //var solids = Extension.GeometryElementExtension.GetSolids(element, element.Document.GetUseView());
            //foreach (var solid in solids)
            //{
            //    foreach (Edge edge in solid.Edges)
            //    {
            //        xyzs.AddRange(edge.Tessellate());
            //    }
            //}
            var curves= Extension.GeometryElementExtension.GetGeometryObjects<Curve>(element, element.Document.GetUseView(), true);
            foreach (var curve in curves)
            {
                xyzs.AddRange(curve.Tessellate());
            }
            return xyzs.Distinct(new XyzEqualComparer()).ToList();
        }

        /// <summary>
        /// 获取墙的轮廓线
        /// </summary>
        /// <param name="wall"></param>
        /// <returns></returns>
        public static List<List<XYZ>> GetWallPolygon(Wall wall)
        {
            /* 方案1:
             * 1找到墙的定位线,
             * 2将定位线拆分成多段
             * 3按照宽度,将多段定位线生成闭合区域
             * 方案2:
             * 直接去墙的顶面,过滤相关face形成轮廓
             */
            List<List<XYZ>> polygons = new List<List<XYZ>>();
            #region 过滤墙的顶面         
            List<PlanarFace> faces = wall.GetBottomFaces();
            #endregion
            foreach (PlanarFace face in faces)
            {
                foreach (CurveLoop curveLoop in face.GetEdgesAsCurveLoops())
                {
                    if (curveLoop == null)
                    {
                        continue;
                    }
                    var polygon = curveLoop.GetPolygon();
                    if (polygon.Any())
                    {
                        polygons.Add(polygon);
                    }
                }
            }
            return polygons;
        }
    }
}